1
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
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