linux/tools/crypto/getstat.c
<<
>>
Prefs
   1/* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */
   2#include <errno.h>
   3#include <linux/cryptouser.h>
   4#include <linux/netlink.h>
   5#include <linux/rtnetlink.h>
   6#include <sys/types.h>
   7#include <sys/socket.h>
   8#include <stdlib.h>
   9#include <stdio.h>
  10#include <string.h>
  11#include <time.h>
  12#include <unistd.h>
  13
  14#define CR_RTA(x)  ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg))))
  15
  16static int get_stat(const char *drivername)
  17{
  18        struct {
  19                struct nlmsghdr n;
  20                struct crypto_user_alg cru;
  21        } req;
  22        struct sockaddr_nl nl;
  23        int sd = 0, ret;
  24        socklen_t addr_len;
  25        struct iovec iov;
  26        struct msghdr msg;
  27        char buf[4096];
  28        struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
  29        struct crypto_user_alg *cru_res = NULL;
  30        int res_len = 0;
  31        struct rtattr *tb[CRYPTOCFGA_MAX + 1];
  32        struct rtattr *rta;
  33        struct nlmsgerr *errmsg;
  34
  35        memset(&req, 0, sizeof(req));
  36        memset(&buf, 0, sizeof(buf));
  37        memset(&msg, 0, sizeof(msg));
  38
  39        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru));
  40        req.n.nlmsg_flags = NLM_F_REQUEST;
  41        req.n.nlmsg_type = CRYPTO_MSG_GETSTAT;
  42        req.n.nlmsg_seq = time(NULL);
  43
  44        strncpy(req.cru.cru_driver_name, drivername, strlen(drivername));
  45
  46        sd =  socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO);
  47        if (sd < 0) {
  48                fprintf(stderr, "Netlink error: cannot open netlink socket");
  49                return -errno;
  50        }
  51        memset(&nl, 0, sizeof(nl));
  52        nl.nl_family = AF_NETLINK;
  53        if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) {
  54                ret = -errno;
  55                fprintf(stderr, "Netlink error: cannot bind netlink socket");
  56                goto out;
  57        }
  58
  59        /* sanity check that netlink socket was successfully opened */
  60        addr_len = sizeof(nl);
  61        if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) {
  62                ret = -errno;
  63                printf("Netlink error: cannot getsockname");
  64                goto out;
  65        }
  66        if (addr_len != sizeof(nl)) {
  67                ret = -errno;
  68                printf("Netlink error: wrong address length %d", addr_len);
  69                goto out;
  70        }
  71        if (nl.nl_family != AF_NETLINK) {
  72                ret = -errno;
  73                printf("Netlink error: wrong address family %d",
  74                                nl.nl_family);
  75                goto out;
  76        }
  77
  78        memset(&nl, 0, sizeof(nl));
  79        nl.nl_family = AF_NETLINK;
  80        iov.iov_base = (void *)&req.n;
  81        iov.iov_len = req.n.nlmsg_len;
  82        msg.msg_name = &nl;
  83        msg.msg_namelen = sizeof(nl);
  84        msg.msg_iov = &iov;
  85        msg.msg_iovlen = 1;
  86        if (sendmsg(sd, &msg, 0) < 0) {
  87                ret = -errno;
  88                printf("Netlink error: sendmsg failed");
  89                goto out;
  90        }
  91        memset(buf, 0, sizeof(buf));
  92        iov.iov_base = buf;
  93        while (1) {
  94                iov.iov_len = sizeof(buf);
  95                ret = recvmsg(sd, &msg, 0);
  96                if (ret < 0) {
  97                        if (errno == EINTR || errno == EAGAIN)
  98                                continue;
  99                        ret = -errno;
 100                        printf("Netlink error: netlink receive error");
 101                        goto out;
 102                }
 103                if (ret == 0) {
 104                        ret = -errno;
 105                        printf("Netlink error: no data");
 106                        goto out;
 107                }
 108                if (ret > sizeof(buf)) {
 109                        ret = -errno;
 110                        printf("Netlink error: received too much data");
 111                        goto out;
 112                }
 113                break;
 114        }
 115
 116        ret = -EFAULT;
 117        res_len = res_n->nlmsg_len;
 118        if (res_n->nlmsg_type == NLMSG_ERROR) {
 119                errmsg = NLMSG_DATA(res_n);
 120                fprintf(stderr, "Fail with %d\n", errmsg->error);
 121                ret = errmsg->error;
 122                goto out;
 123        }
 124
 125        if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) {
 126                cru_res = NLMSG_DATA(res_n);
 127                res_len -= NLMSG_SPACE(sizeof(*cru_res));
 128        }
 129        if (res_len < 0) {
 130                printf("Netlink error: nlmsg len %d\n", res_len);
 131                goto out;
 132        }
 133
 134        if (!cru_res) {
 135                ret = -EFAULT;
 136                printf("Netlink error: no cru_res\n");
 137                goto out;
 138        }
 139
 140        rta = CR_RTA(cru_res);
 141        memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1));
 142        while (RTA_OK(rta, res_len)) {
 143                if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type]))
 144                        tb[rta->rta_type] = rta;
 145                rta = RTA_NEXT(rta, res_len);
 146        }
 147        if (res_len) {
 148                printf("Netlink error: unprocessed data %d",
 149                                res_len);
 150                goto out;
 151        }
 152
 153        if (tb[CRYPTOCFGA_STAT_HASH]) {
 154                struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH];
 155                struct crypto_stat_hash *rhash =
 156                        (struct crypto_stat_hash *)RTA_DATA(rta);
 157                printf("%s\tHash\n\tHash: %llu bytes: %llu\n\tErrors: %llu\n",
 158                        drivername,
 159                        rhash->stat_hash_cnt, rhash->stat_hash_tlen,
 160                        rhash->stat_err_cnt);
 161        } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) {
 162                struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS];
 163                struct crypto_stat_compress *rblk =
 164                        (struct crypto_stat_compress *)RTA_DATA(rta);
 165                printf("%s\tCompress\n\tCompress: %llu bytes: %llu\n\tDecompress: %llu bytes: %llu\n\tErrors: %llu\n",
 166                        drivername,
 167                        rblk->stat_compress_cnt, rblk->stat_compress_tlen,
 168                        rblk->stat_decompress_cnt, rblk->stat_decompress_tlen,
 169                        rblk->stat_err_cnt);
 170        } else if (tb[CRYPTOCFGA_STAT_ACOMP]) {
 171                struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP];
 172                struct crypto_stat_compress *rcomp =
 173                        (struct crypto_stat_compress *)RTA_DATA(rta);
 174                printf("%s\tACompress\n\tCompress: %llu bytes: %llu\n\tDecompress: %llu bytes: %llu\n\tErrors: %llu\n",
 175                        drivername,
 176                        rcomp->stat_compress_cnt, rcomp->stat_compress_tlen,
 177                        rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen,
 178                        rcomp->stat_err_cnt);
 179        } else if (tb[CRYPTOCFGA_STAT_AEAD]) {
 180                struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD];
 181                struct crypto_stat_aead *raead =
 182                        (struct crypto_stat_aead *)RTA_DATA(rta);
 183                printf("%s\tAEAD\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n",
 184                        drivername,
 185                        raead->stat_encrypt_cnt, raead->stat_encrypt_tlen,
 186                        raead->stat_decrypt_cnt, raead->stat_decrypt_tlen,
 187                        raead->stat_err_cnt);
 188        } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) {
 189                struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER];
 190                struct crypto_stat_cipher *rblk =
 191                        (struct crypto_stat_cipher *)RTA_DATA(rta);
 192                printf("%s\tCipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n",
 193                        drivername,
 194                        rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
 195                        rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
 196                        rblk->stat_err_cnt);
 197        } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) {
 198                struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER];
 199                struct crypto_stat_akcipher *rblk =
 200                        (struct crypto_stat_akcipher *)RTA_DATA(rta);
 201                printf("%s\tAkcipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tSign: %llu\n\tVerify: %llu\n\tErrors: %llu\n",
 202                        drivername,
 203                        rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
 204                        rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
 205                        rblk->stat_sign_cnt, rblk->stat_verify_cnt,
 206                        rblk->stat_err_cnt);
 207        } else if (tb[CRYPTOCFGA_STAT_CIPHER]) {
 208                struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER];
 209                struct crypto_stat_cipher *rblk =
 210                        (struct crypto_stat_cipher *)RTA_DATA(rta);
 211                printf("%s\tcipher\n\tEncrypt: %llu bytes: %llu\n\tDecrypt: %llu bytes: %llu\n\tErrors: %llu\n",
 212                        drivername,
 213                        rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
 214                        rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
 215                        rblk->stat_err_cnt);
 216        } else if (tb[CRYPTOCFGA_STAT_RNG]) {
 217                struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG];
 218                struct crypto_stat_rng *rrng =
 219                        (struct crypto_stat_rng *)RTA_DATA(rta);
 220                printf("%s\tRNG\n\tSeed: %llu\n\tGenerate: %llu bytes: %llu\n\tErrors: %llu\n",
 221                        drivername,
 222                        rrng->stat_seed_cnt,
 223                        rrng->stat_generate_cnt, rrng->stat_generate_tlen,
 224                        rrng->stat_err_cnt);
 225        } else if (tb[CRYPTOCFGA_STAT_KPP]) {
 226                struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP];
 227                struct crypto_stat_kpp *rkpp =
 228                        (struct crypto_stat_kpp *)RTA_DATA(rta);
 229                printf("%s\tKPP\n\tSetsecret: %llu\n\tGenerate public key: %llu\n\tCompute_shared_secret: %llu\n\tErrors: %llu\n",
 230                        drivername,
 231                        rkpp->stat_setsecret_cnt,
 232                        rkpp->stat_generate_public_key_cnt,
 233                        rkpp->stat_compute_shared_secret_cnt,
 234                        rkpp->stat_err_cnt);
 235        } else {
 236                fprintf(stderr, "%s is of an unknown algorithm\n", drivername);
 237        }
 238        ret = 0;
 239out:
 240        close(sd);
 241        return ret;
 242}
 243
 244int main(int argc, const char *argv[])
 245{
 246        char buf[4096];
 247        FILE *procfd;
 248        int i, lastspace;
 249        int ret;
 250
 251        procfd = fopen("/proc/crypto", "r");
 252        if (!procfd) {
 253                ret = errno;
 254                fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno));
 255                return ret;
 256        }
 257        if (argc > 1) {
 258                if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
 259                        printf("Usage: %s [-h|--help] display this help\n", argv[0]);
 260                        printf("Usage: %s display all crypto statistics\n", argv[0]);
 261                        printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]);
 262                        return 0;
 263                }
 264                for (i = 1; i < argc; i++) {
 265                        ret = get_stat(argv[i]);
 266                        if (ret) {
 267                                fprintf(stderr, "Failed with %s\n", strerror(-ret));
 268                                return ret;
 269                        }
 270                }
 271                return 0;
 272        }
 273
 274        while (fgets(buf, sizeof(buf), procfd)) {
 275                if (!strncmp(buf, "driver", 6)) {
 276                        lastspace = 0;
 277                        i = 0;
 278                        while (i < strlen(buf)) {
 279                                i++;
 280                                if (buf[i] == ' ')
 281                                        lastspace = i;
 282                        }
 283                        buf[strlen(buf) - 1] = '\0';
 284                        ret = get_stat(buf + lastspace + 1);
 285                        if (ret) {
 286                                fprintf(stderr, "Failed with %s\n", strerror(-ret));
 287                                goto out;
 288                        }
 289                }
 290        }
 291out:
 292        fclose(procfd);
 293        return ret;
 294}
 295