]>
Commit | Line | Data |
---|---|---|
a6f37cee CL |
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 | ||
16 | static 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]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
158 | drivername, |
159 | rhash->stat_hash_cnt, rhash->stat_hash_tlen, | |
44f13133 | 160 | rhash->stat_err_cnt); |
a6f37cee CL |
161 | } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) { |
162 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
166 | drivername, |
167 | rblk->stat_compress_cnt, rblk->stat_compress_tlen, | |
168 | rblk->stat_decompress_cnt, rblk->stat_decompress_tlen, | |
44f13133 | 169 | rblk->stat_err_cnt); |
a6f37cee CL |
170 | } else if (tb[CRYPTOCFGA_STAT_ACOMP]) { |
171 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
175 | drivername, |
176 | rcomp->stat_compress_cnt, rcomp->stat_compress_tlen, | |
177 | rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen, | |
44f13133 | 178 | rcomp->stat_err_cnt); |
a6f37cee CL |
179 | } else if (tb[CRYPTOCFGA_STAT_AEAD]) { |
180 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
184 | drivername, |
185 | raead->stat_encrypt_cnt, raead->stat_encrypt_tlen, | |
186 | raead->stat_decrypt_cnt, raead->stat_decrypt_tlen, | |
44f13133 | 187 | raead->stat_err_cnt); |
a6f37cee CL |
188 | } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) { |
189 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
193 | drivername, |
194 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | |
195 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | |
44f13133 | 196 | rblk->stat_err_cnt); |
a6f37cee CL |
197 | } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) { |
198 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
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, | |
44f13133 | 206 | rblk->stat_err_cnt); |
a6f37cee CL |
207 | } else if (tb[CRYPTOCFGA_STAT_CIPHER]) { |
208 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
212 | drivername, |
213 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | |
214 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | |
44f13133 | 215 | rblk->stat_err_cnt); |
a6f37cee CL |
216 | } else if (tb[CRYPTOCFGA_STAT_RNG]) { |
217 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
221 | drivername, |
222 | rrng->stat_seed_cnt, | |
223 | rrng->stat_generate_cnt, rrng->stat_generate_tlen, | |
44f13133 | 224 | rrng->stat_err_cnt); |
a6f37cee CL |
225 | } else if (tb[CRYPTOCFGA_STAT_KPP]) { |
226 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP]; | |
76d09ea7 CL |
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", | |
a6f37cee CL |
230 | drivername, |
231 | rkpp->stat_setsecret_cnt, | |
232 | rkpp->stat_generate_public_key_cnt, | |
233 | rkpp->stat_compute_shared_secret_cnt, | |
44f13133 | 234 | rkpp->stat_err_cnt); |
a6f37cee CL |
235 | } else { |
236 | fprintf(stderr, "%s is of an unknown algorithm\n", drivername); | |
237 | } | |
238 | ret = 0; | |
239 | out: | |
240 | close(sd); | |
241 | return ret; | |
242 | } | |
243 | ||
244 | int 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 | } | |
291 | out: | |
292 | fclose(procfd); | |
293 | return ret; | |
294 | } |