| 1 | /* |
| 2 | * An OCF module that uses Intels IXP CryptACC API to do the crypto. |
| 3 | * This driver requires the IXP400 Access Library that is available |
| 4 | * from Intel in order to operate (or compile). |
| 5 | * |
| 6 | * Written by David McCullough <david_mccullough@securecomputing.com> |
| 7 | * Copyright (C) 2006-2007 David McCullough |
| 8 | * Copyright (C) 2004-2005 Intel Corporation. |
| 9 | * |
| 10 | * LICENSE TERMS |
| 11 | * |
| 12 | * The free distribution and use of this software in both source and binary |
| 13 | * form is allowed (with or without changes) provided that: |
| 14 | * |
| 15 | * 1. distributions of this source code include the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer; |
| 17 | * |
| 18 | * 2. distributions in binary form include the above copyright |
| 19 | * notice, this list of conditions and the following disclaimer |
| 20 | * in the documentation and/or other associated materials; |
| 21 | * |
| 22 | * 3. the copyright holder's name is not used to endorse products |
| 23 | * built using this software without specific written permission. |
| 24 | * |
| 25 | * ALTERNATIVELY, provided that this notice is retained in full, this product |
| 26 | * may be distributed under the terms of the GNU General Public License (GPL), |
| 27 | * in which case the provisions of the GPL apply INSTEAD OF those given above. |
| 28 | * |
| 29 | * DISCLAIMER |
| 30 | * |
| 31 | * This software is provided 'as is' with no explicit or implied warranties |
| 32 | * in respect of its properties, including, but not limited to, correctness |
| 33 | * and/or fitness for purpose. |
| 34 | */ |
| 35 | |
| 36 | #ifndef AUTOCONF_INCLUDED |
| 37 | #include <linux/config.h> |
| 38 | #endif |
| 39 | #include <linux/module.h> |
| 40 | #include <linux/init.h> |
| 41 | #include <linux/list.h> |
| 42 | #include <linux/slab.h> |
| 43 | #include <linux/sched.h> |
| 44 | #include <linux/wait.h> |
| 45 | #include <linux/crypto.h> |
| 46 | #include <linux/interrupt.h> |
| 47 | #include <asm/scatterlist.h> |
| 48 | |
| 49 | #include <IxTypes.h> |
| 50 | #include <IxOsBuffMgt.h> |
| 51 | #include <IxNpeDl.h> |
| 52 | #include <IxCryptoAcc.h> |
| 53 | #include <IxQMgr.h> |
| 54 | #include <IxOsServices.h> |
| 55 | #include <IxOsCacheMMU.h> |
| 56 | |
| 57 | #include <cryptodev.h> |
| 58 | #include <uio.h> |
| 59 | |
| 60 | #ifndef IX_MBUF_PRIV |
| 61 | #define IX_MBUF_PRIV(x) ((x)->priv) |
| 62 | #endif |
| 63 | |
| 64 | struct ixp_data; |
| 65 | |
| 66 | struct ixp_q { |
| 67 | struct list_head ixp_q_list; |
| 68 | struct ixp_data *ixp_q_data; |
| 69 | struct cryptop *ixp_q_crp; |
| 70 | struct cryptodesc *ixp_q_ccrd; |
| 71 | struct cryptodesc *ixp_q_acrd; |
| 72 | IX_MBUF ixp_q_mbuf; |
| 73 | UINT8 *ixp_hash_dest; /* Location for hash in client buffer */ |
| 74 | UINT8 *ixp_hash_src; /* Location of hash in internal buffer */ |
| 75 | unsigned char ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH]; |
| 76 | unsigned char *ixp_q_iv; |
| 77 | }; |
| 78 | |
| 79 | struct ixp_data { |
| 80 | int ixp_registered; /* is the context registered */ |
| 81 | int ixp_crd_flags; /* detect direction changes */ |
| 82 | |
| 83 | int ixp_cipher_alg; |
| 84 | int ixp_auth_alg; |
| 85 | |
| 86 | UINT32 ixp_ctx_id; |
| 87 | UINT32 ixp_hash_key_id; /* used when hashing */ |
| 88 | IxCryptoAccCtx ixp_ctx; |
| 89 | IX_MBUF ixp_pri_mbuf; |
| 90 | IX_MBUF ixp_sec_mbuf; |
| 91 | |
| 92 | struct work_struct ixp_pending_work; |
| 93 | struct work_struct ixp_registration_work; |
| 94 | struct list_head ixp_q; /* unprocessed requests */ |
| 95 | }; |
| 96 | |
| 97 | #ifdef __ixp46X |
| 98 | |
| 99 | #define MAX_IOP_SIZE 64 /* words */ |
| 100 | #define MAX_OOP_SIZE 128 |
| 101 | |
| 102 | #define MAX_PARAMS 3 |
| 103 | |
| 104 | struct ixp_pkq { |
| 105 | struct list_head pkq_list; |
| 106 | struct cryptkop *pkq_krp; |
| 107 | |
| 108 | IxCryptoAccPkeEauInOperands pkq_op; |
| 109 | IxCryptoAccPkeEauOpResult pkq_result; |
| 110 | |
| 111 | UINT32 pkq_ibuf0[MAX_IOP_SIZE]; |
| 112 | UINT32 pkq_ibuf1[MAX_IOP_SIZE]; |
| 113 | UINT32 pkq_ibuf2[MAX_IOP_SIZE]; |
| 114 | UINT32 pkq_obuf[MAX_OOP_SIZE]; |
| 115 | }; |
| 116 | |
| 117 | static LIST_HEAD(ixp_pkq); /* current PK wait list */ |
| 118 | static struct ixp_pkq *ixp_pk_cur; |
| 119 | static spinlock_t ixp_pkq_lock; |
| 120 | |
| 121 | #endif /* __ixp46X */ |
| 122 | |
| 123 | static int ixp_blocked = 0; |
| 124 | |
| 125 | static int32_t ixp_id = -1; |
| 126 | static struct ixp_data **ixp_sessions = NULL; |
| 127 | static u_int32_t ixp_sesnum = 0; |
| 128 | |
| 129 | static int ixp_process(device_t, struct cryptop *, int); |
| 130 | static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *); |
| 131 | static int ixp_freesession(device_t, u_int64_t); |
| 132 | #ifdef __ixp46X |
| 133 | static int ixp_kprocess(device_t, struct cryptkop *krp, int hint); |
| 134 | #endif |
| 135 | |
| 136 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) |
| 137 | static kmem_cache_t *qcache; |
| 138 | #else |
| 139 | static struct kmem_cache *qcache; |
| 140 | #endif |
| 141 | |
| 142 | #define debug ixp_debug |
| 143 | static int ixp_debug = 0; |
| 144 | module_param(ixp_debug, int, 0644); |
| 145 | MODULE_PARM_DESC(ixp_debug, "Enable debug"); |
| 146 | |
| 147 | static int ixp_init_crypto = 1; |
| 148 | module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */ |
| 149 | MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)"); |
| 150 | |
| 151 | static void ixp_process_pending(void *arg); |
| 152 | static void ixp_registration(void *arg); |
| 153 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 154 | static void ixp_process_pending_wq(struct work_struct *work); |
| 155 | static void ixp_registration_wq(struct work_struct *work); |
| 156 | #endif |
| 157 | |
| 158 | /* |
| 159 | * dummy device structure |
| 160 | */ |
| 161 | |
| 162 | static struct { |
| 163 | softc_device_decl sc_dev; |
| 164 | } ixpdev; |
| 165 | |
| 166 | static device_method_t ixp_methods = { |
| 167 | /* crypto device methods */ |
| 168 | DEVMETHOD(cryptodev_newsession, ixp_newsession), |
| 169 | DEVMETHOD(cryptodev_freesession,ixp_freesession), |
| 170 | DEVMETHOD(cryptodev_process, ixp_process), |
| 171 | #ifdef __ixp46X |
| 172 | DEVMETHOD(cryptodev_kprocess, ixp_kprocess), |
| 173 | #endif |
| 174 | }; |
| 175 | |
| 176 | /* |
| 177 | * Generate a new software session. |
| 178 | */ |
| 179 | static int |
| 180 | ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) |
| 181 | { |
| 182 | struct ixp_data *ixp; |
| 183 | u_int32_t i; |
| 184 | #define AUTH_LEN(cri, def) \ |
| 185 | (cri->cri_mlen ? cri->cri_mlen : (def)) |
| 186 | |
| 187 | dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg); |
| 188 | if (sid == NULL || cri == NULL) { |
| 189 | dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); |
| 190 | return EINVAL; |
| 191 | } |
| 192 | |
| 193 | if (ixp_sessions) { |
| 194 | for (i = 1; i < ixp_sesnum; i++) |
| 195 | if (ixp_sessions[i] == NULL) |
| 196 | break; |
| 197 | } else |
| 198 | i = 1; /* NB: to silence compiler warning */ |
| 199 | |
| 200 | if (ixp_sessions == NULL || i == ixp_sesnum) { |
| 201 | struct ixp_data **ixpd; |
| 202 | |
| 203 | if (ixp_sessions == NULL) { |
| 204 | i = 1; /* We leave ixp_sessions[0] empty */ |
| 205 | ixp_sesnum = CRYPTO_SW_SESSIONS; |
| 206 | } else |
| 207 | ixp_sesnum *= 2; |
| 208 | |
| 209 | ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC); |
| 210 | if (ixpd == NULL) { |
| 211 | /* Reset session number */ |
| 212 | if (ixp_sesnum == CRYPTO_SW_SESSIONS) |
| 213 | ixp_sesnum = 0; |
| 214 | else |
| 215 | ixp_sesnum /= 2; |
| 216 | dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); |
| 217 | return ENOBUFS; |
| 218 | } |
| 219 | memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *)); |
| 220 | |
| 221 | /* Copy existing sessions */ |
| 222 | if (ixp_sessions) { |
| 223 | memcpy(ixpd, ixp_sessions, |
| 224 | (ixp_sesnum / 2) * sizeof(struct ixp_data *)); |
| 225 | kfree(ixp_sessions); |
| 226 | } |
| 227 | |
| 228 | ixp_sessions = ixpd; |
| 229 | } |
| 230 | |
| 231 | ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data), |
| 232 | SLAB_ATOMIC); |
| 233 | if (ixp_sessions[i] == NULL) { |
| 234 | ixp_freesession(NULL, i); |
| 235 | dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); |
| 236 | return ENOBUFS; |
| 237 | } |
| 238 | |
| 239 | *sid = i; |
| 240 | |
| 241 | ixp = ixp_sessions[i]; |
| 242 | memset(ixp, 0, sizeof(*ixp)); |
| 243 | |
| 244 | ixp->ixp_cipher_alg = -1; |
| 245 | ixp->ixp_auth_alg = -1; |
| 246 | ixp->ixp_ctx_id = -1; |
| 247 | INIT_LIST_HEAD(&ixp->ixp_q); |
| 248 | |
| 249 | ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0; |
| 250 | |
| 251 | while (cri) { |
| 252 | switch (cri->cri_alg) { |
| 253 | case CRYPTO_DES_CBC: |
| 254 | ixp->ixp_cipher_alg = cri->cri_alg; |
| 255 | ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES; |
| 256 | ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; |
| 257 | ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; |
| 258 | ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; |
| 259 | ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = |
| 260 | IX_CRYPTO_ACC_DES_IV_64; |
| 261 | memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, |
| 262 | cri->cri_key, (cri->cri_klen + 7) / 8); |
| 263 | break; |
| 264 | |
| 265 | case CRYPTO_3DES_CBC: |
| 266 | ixp->ixp_cipher_alg = cri->cri_alg; |
| 267 | ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; |
| 268 | ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; |
| 269 | ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; |
| 270 | ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; |
| 271 | ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = |
| 272 | IX_CRYPTO_ACC_DES_IV_64; |
| 273 | memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, |
| 274 | cri->cri_key, (cri->cri_klen + 7) / 8); |
| 275 | break; |
| 276 | |
| 277 | case CRYPTO_RIJNDAEL128_CBC: |
| 278 | ixp->ixp_cipher_alg = cri->cri_alg; |
| 279 | ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES; |
| 280 | ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; |
| 281 | ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; |
| 282 | ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16; |
| 283 | ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16; |
| 284 | memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, |
| 285 | cri->cri_key, (cri->cri_klen + 7) / 8); |
| 286 | break; |
| 287 | |
| 288 | case CRYPTO_MD5: |
| 289 | case CRYPTO_MD5_HMAC: |
| 290 | ixp->ixp_auth_alg = cri->cri_alg; |
| 291 | ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5; |
| 292 | ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN); |
| 293 | ixp->ixp_ctx.authCtx.aadLen = 0; |
| 294 | /* Only MD5_HMAC needs a key */ |
| 295 | if (cri->cri_alg == CRYPTO_MD5_HMAC) { |
| 296 | ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; |
| 297 | if (ixp->ixp_ctx.authCtx.authKeyLen > |
| 298 | sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { |
| 299 | printk( |
| 300 | "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n", |
| 301 | cri->cri_klen); |
| 302 | ixp_freesession(NULL, i); |
| 303 | return EINVAL; |
| 304 | } |
| 305 | memcpy(ixp->ixp_ctx.authCtx.key.authKey, |
| 306 | cri->cri_key, (cri->cri_klen + 7) / 8); |
| 307 | } |
| 308 | break; |
| 309 | |
| 310 | case CRYPTO_SHA1: |
| 311 | case CRYPTO_SHA1_HMAC: |
| 312 | ixp->ixp_auth_alg = cri->cri_alg; |
| 313 | ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; |
| 314 | ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN); |
| 315 | ixp->ixp_ctx.authCtx.aadLen = 0; |
| 316 | /* Only SHA1_HMAC needs a key */ |
| 317 | if (cri->cri_alg == CRYPTO_SHA1_HMAC) { |
| 318 | ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; |
| 319 | if (ixp->ixp_ctx.authCtx.authKeyLen > |
| 320 | sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { |
| 321 | printk( |
| 322 | "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n", |
| 323 | cri->cri_klen); |
| 324 | ixp_freesession(NULL, i); |
| 325 | return EINVAL; |
| 326 | } |
| 327 | memcpy(ixp->ixp_ctx.authCtx.key.authKey, |
| 328 | cri->cri_key, (cri->cri_klen + 7) / 8); |
| 329 | } |
| 330 | break; |
| 331 | |
| 332 | default: |
| 333 | printk("ixp: unknown algo 0x%x\n", cri->cri_alg); |
| 334 | ixp_freesession(NULL, i); |
| 335 | return EINVAL; |
| 336 | } |
| 337 | cri = cri->cri_next; |
| 338 | } |
| 339 | |
| 340 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 341 | INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq); |
| 342 | INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq); |
| 343 | #else |
| 344 | INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp); |
| 345 | INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp); |
| 346 | #endif |
| 347 | |
| 348 | return 0; |
| 349 | } |
| 350 | |
| 351 | |
| 352 | /* |
| 353 | * Free a session. |
| 354 | */ |
| 355 | static int |
| 356 | ixp_freesession(device_t dev, u_int64_t tid) |
| 357 | { |
| 358 | u_int32_t sid = CRYPTO_SESID2LID(tid); |
| 359 | |
| 360 | dprintk("%s()\n", __FUNCTION__); |
| 361 | if (sid > ixp_sesnum || ixp_sessions == NULL || |
| 362 | ixp_sessions[sid] == NULL) { |
| 363 | dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); |
| 364 | return EINVAL; |
| 365 | } |
| 366 | |
| 367 | /* Silently accept and return */ |
| 368 | if (sid == 0) |
| 369 | return 0; |
| 370 | |
| 371 | if (ixp_sessions[sid]) { |
| 372 | if (ixp_sessions[sid]->ixp_ctx_id != -1) { |
| 373 | ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id); |
| 374 | ixp_sessions[sid]->ixp_ctx_id = -1; |
| 375 | } |
| 376 | |
| 377 | flush_scheduled_work(); |
| 378 | |
| 379 | kfree(ixp_sessions[sid]); |
| 380 | } |
| 381 | ixp_sessions[sid] = NULL; |
| 382 | if (ixp_blocked) { |
| 383 | ixp_blocked = 0; |
| 384 | crypto_unblock(ixp_id, CRYPTO_SYMQ); |
| 385 | } |
| 386 | return 0; |
| 387 | } |
| 388 | |
| 389 | |
| 390 | /* |
| 391 | * callback for when hash processing is complete |
| 392 | */ |
| 393 | |
| 394 | static void |
| 395 | ixp_hash_perform_cb( |
| 396 | UINT32 hash_key_id, |
| 397 | IX_MBUF *bufp, |
| 398 | IxCryptoAccStatus status) |
| 399 | { |
| 400 | struct ixp_q *q; |
| 401 | |
| 402 | dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status); |
| 403 | |
| 404 | if (bufp == NULL) { |
| 405 | printk("ixp: NULL buf in %s\n", __FUNCTION__); |
| 406 | return; |
| 407 | } |
| 408 | |
| 409 | q = IX_MBUF_PRIV(bufp); |
| 410 | if (q == NULL) { |
| 411 | printk("ixp: NULL priv in %s\n", __FUNCTION__); |
| 412 | return; |
| 413 | } |
| 414 | |
| 415 | if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 416 | /* On success, need to copy hash back into original client buffer */ |
| 417 | memcpy(q->ixp_hash_dest, q->ixp_hash_src, |
| 418 | (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ? |
| 419 | SHA1_HASH_LEN : MD5_HASH_LEN); |
| 420 | } |
| 421 | else { |
| 422 | printk("ixp: hash perform failed status=%d\n", status); |
| 423 | q->ixp_q_crp->crp_etype = EINVAL; |
| 424 | } |
| 425 | |
| 426 | /* Free internal buffer used for hashing */ |
| 427 | kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf)); |
| 428 | |
| 429 | crypto_done(q->ixp_q_crp); |
| 430 | kmem_cache_free(qcache, q); |
| 431 | } |
| 432 | |
| 433 | /* |
| 434 | * setup a request and perform it |
| 435 | */ |
| 436 | static void |
| 437 | ixp_q_process(struct ixp_q *q) |
| 438 | { |
| 439 | IxCryptoAccStatus status; |
| 440 | struct ixp_data *ixp = q->ixp_q_data; |
| 441 | int auth_off = 0; |
| 442 | int auth_len = 0; |
| 443 | int crypt_off = 0; |
| 444 | int crypt_len = 0; |
| 445 | int icv_off = 0; |
| 446 | char *crypt_func; |
| 447 | |
| 448 | dprintk("%s(%p)\n", __FUNCTION__, q); |
| 449 | |
| 450 | if (q->ixp_q_ccrd) { |
| 451 | if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) { |
| 452 | q->ixp_q_iv = q->ixp_q_ccrd->crd_iv; |
| 453 | } else { |
| 454 | q->ixp_q_iv = q->ixp_q_iv_data; |
| 455 | crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf, |
| 456 | q->ixp_q_ccrd->crd_inject, |
| 457 | ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen, |
| 458 | (caddr_t) q->ixp_q_iv); |
| 459 | } |
| 460 | |
| 461 | if (q->ixp_q_acrd) { |
| 462 | auth_off = q->ixp_q_acrd->crd_skip; |
| 463 | auth_len = q->ixp_q_acrd->crd_len; |
| 464 | icv_off = q->ixp_q_acrd->crd_inject; |
| 465 | } |
| 466 | |
| 467 | crypt_off = q->ixp_q_ccrd->crd_skip; |
| 468 | crypt_len = q->ixp_q_ccrd->crd_len; |
| 469 | } else { /* if (q->ixp_q_acrd) */ |
| 470 | auth_off = q->ixp_q_acrd->crd_skip; |
| 471 | auth_len = q->ixp_q_acrd->crd_len; |
| 472 | icv_off = q->ixp_q_acrd->crd_inject; |
| 473 | } |
| 474 | |
| 475 | if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) { |
| 476 | struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf; |
| 477 | if (skb_shinfo(skb)->nr_frags) { |
| 478 | /* |
| 479 | * DAVIDM fix this limitation one day by using |
| 480 | * a buffer pool and chaining, it is not currently |
| 481 | * needed for current user/kernel space acceleration |
| 482 | */ |
| 483 | printk("ixp: Cannot handle fragmented skb's yet !\n"); |
| 484 | q->ixp_q_crp->crp_etype = ENOENT; |
| 485 | goto done; |
| 486 | } |
| 487 | IX_MBUF_MLEN(&q->ixp_q_mbuf) = |
| 488 | IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = skb->len; |
| 489 | IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data; |
| 490 | } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) { |
| 491 | struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf; |
| 492 | if (uiop->uio_iovcnt != 1) { |
| 493 | /* |
| 494 | * DAVIDM fix this limitation one day by using |
| 495 | * a buffer pool and chaining, it is not currently |
| 496 | * needed for current user/kernel space acceleration |
| 497 | */ |
| 498 | printk("ixp: Cannot handle more than 1 iovec yet !\n"); |
| 499 | q->ixp_q_crp->crp_etype = ENOENT; |
| 500 | goto done; |
| 501 | } |
| 502 | IX_MBUF_MLEN(&q->ixp_q_mbuf) = |
| 503 | IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len; |
| 504 | IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base; |
| 505 | } else /* contig buffer */ { |
| 506 | IX_MBUF_MLEN(&q->ixp_q_mbuf) = |
| 507 | IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen; |
| 508 | IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf; |
| 509 | } |
| 510 | |
| 511 | IX_MBUF_PRIV(&q->ixp_q_mbuf) = q; |
| 512 | |
| 513 | if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) { |
| 514 | /* |
| 515 | * For SHA1 and MD5 hash, need to create an internal buffer that is big |
| 516 | * enough to hold the original data + the appropriate padding for the |
| 517 | * hash algorithm. |
| 518 | */ |
| 519 | UINT8 *tbuf = NULL; |
| 520 | |
| 521 | IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = |
| 522 | ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8; |
| 523 | tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC); |
| 524 | |
| 525 | if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) { |
| 526 | printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n", |
| 527 | IX_MBUF_MLEN(&q->ixp_q_mbuf)); |
| 528 | q->ixp_q_crp->crp_etype = ENOMEM; |
| 529 | goto done; |
| 530 | } |
| 531 | memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len); |
| 532 | |
| 533 | /* Set location in client buffer to copy hash into */ |
| 534 | q->ixp_hash_dest = |
| 535 | &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len]; |
| 536 | |
| 537 | IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf; |
| 538 | |
| 539 | /* Set location in internal buffer for where hash starts */ |
| 540 | q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len]; |
| 541 | |
| 542 | crypt_func = "ixCryptoAccHashPerform"; |
| 543 | status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo, |
| 544 | &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len, |
| 545 | &ixp->ixp_hash_key_id); |
| 546 | } |
| 547 | else { |
| 548 | crypt_func = "ixCryptoAccAuthCryptPerform"; |
| 549 | status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf, |
| 550 | NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off, |
| 551 | q->ixp_q_iv); |
| 552 | } |
| 553 | |
| 554 | if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) |
| 555 | return; |
| 556 | |
| 557 | if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) { |
| 558 | q->ixp_q_crp->crp_etype = ENOMEM; |
| 559 | goto done; |
| 560 | } |
| 561 | |
| 562 | printk("ixp: %s failed %u\n", crypt_func, status); |
| 563 | q->ixp_q_crp->crp_etype = EINVAL; |
| 564 | |
| 565 | done: |
| 566 | crypto_done(q->ixp_q_crp); |
| 567 | kmem_cache_free(qcache, q); |
| 568 | } |
| 569 | |
| 570 | |
| 571 | /* |
| 572 | * because we cannot process the Q from the Register callback |
| 573 | * we do it here on a task Q. |
| 574 | */ |
| 575 | |
| 576 | static void |
| 577 | ixp_process_pending(void *arg) |
| 578 | { |
| 579 | struct ixp_data *ixp = arg; |
| 580 | struct ixp_q *q = NULL; |
| 581 | |
| 582 | dprintk("%s(%p)\n", __FUNCTION__, arg); |
| 583 | |
| 584 | if (!ixp) |
| 585 | return; |
| 586 | |
| 587 | while (!list_empty(&ixp->ixp_q)) { |
| 588 | q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); |
| 589 | list_del(&q->ixp_q_list); |
| 590 | ixp_q_process(q); |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 595 | static void |
| 596 | ixp_process_pending_wq(struct work_struct *work) |
| 597 | { |
| 598 | struct ixp_data *ixp = container_of(work, struct ixp_data, |
| 599 | ixp_pending_work); |
| 600 | ixp_process_pending(ixp); |
| 601 | } |
| 602 | #endif |
| 603 | |
| 604 | /* |
| 605 | * callback for when context registration is complete |
| 606 | */ |
| 607 | |
| 608 | static void |
| 609 | ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) |
| 610 | { |
| 611 | int i; |
| 612 | struct ixp_data *ixp; |
| 613 | struct ixp_q *q; |
| 614 | |
| 615 | dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status); |
| 616 | |
| 617 | /* |
| 618 | * free any buffer passed in to this routine |
| 619 | */ |
| 620 | if (bufp) { |
| 621 | IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; |
| 622 | kfree(IX_MBUF_MDATA(bufp)); |
| 623 | IX_MBUF_MDATA(bufp) = NULL; |
| 624 | } |
| 625 | |
| 626 | for (i = 0; i < ixp_sesnum; i++) { |
| 627 | ixp = ixp_sessions[i]; |
| 628 | if (ixp && ixp->ixp_ctx_id == ctx_id) |
| 629 | break; |
| 630 | } |
| 631 | if (i >= ixp_sesnum) { |
| 632 | printk("ixp: invalid context id %d\n", ctx_id); |
| 633 | return; |
| 634 | } |
| 635 | |
| 636 | if (IX_CRYPTO_ACC_STATUS_WAIT == status) { |
| 637 | /* this is normal to free the first of two buffers */ |
| 638 | dprintk("ixp: register not finished yet.\n"); |
| 639 | return; |
| 640 | } |
| 641 | |
| 642 | if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { |
| 643 | printk("ixp: register failed 0x%x\n", status); |
| 644 | while (!list_empty(&ixp->ixp_q)) { |
| 645 | q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); |
| 646 | list_del(&q->ixp_q_list); |
| 647 | q->ixp_q_crp->crp_etype = EINVAL; |
| 648 | crypto_done(q->ixp_q_crp); |
| 649 | kmem_cache_free(qcache, q); |
| 650 | } |
| 651 | return; |
| 652 | } |
| 653 | |
| 654 | /* |
| 655 | * we are now registered, we cannot start processing the Q here |
| 656 | * or we get strange errors with AES (DES/3DES seem to be ok). |
| 657 | */ |
| 658 | ixp->ixp_registered = 1; |
| 659 | schedule_work(&ixp->ixp_pending_work); |
| 660 | } |
| 661 | |
| 662 | |
| 663 | /* |
| 664 | * callback for when data processing is complete |
| 665 | */ |
| 666 | |
| 667 | static void |
| 668 | ixp_perform_cb( |
| 669 | UINT32 ctx_id, |
| 670 | IX_MBUF *sbufp, |
| 671 | IX_MBUF *dbufp, |
| 672 | IxCryptoAccStatus status) |
| 673 | { |
| 674 | struct ixp_q *q; |
| 675 | |
| 676 | dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp, |
| 677 | dbufp, status); |
| 678 | |
| 679 | if (sbufp == NULL) { |
| 680 | printk("ixp: NULL sbuf in ixp_perform_cb\n"); |
| 681 | return; |
| 682 | } |
| 683 | |
| 684 | q = IX_MBUF_PRIV(sbufp); |
| 685 | if (q == NULL) { |
| 686 | printk("ixp: NULL priv in ixp_perform_cb\n"); |
| 687 | return; |
| 688 | } |
| 689 | |
| 690 | if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 691 | printk("ixp: perform failed status=%d\n", status); |
| 692 | q->ixp_q_crp->crp_etype = EINVAL; |
| 693 | } |
| 694 | |
| 695 | crypto_done(q->ixp_q_crp); |
| 696 | kmem_cache_free(qcache, q); |
| 697 | } |
| 698 | |
| 699 | |
| 700 | /* |
| 701 | * registration is not callable at IRQ time, so we defer |
| 702 | * to a task queue, this routines completes the registration for us |
| 703 | * when the task queue runs |
| 704 | * |
| 705 | * Unfortunately this means we cannot tell OCF that the driver is blocked, |
| 706 | * we do that on the next request. |
| 707 | */ |
| 708 | |
| 709 | static void |
| 710 | ixp_registration(void *arg) |
| 711 | { |
| 712 | struct ixp_data *ixp = arg; |
| 713 | struct ixp_q *q = NULL; |
| 714 | IX_MBUF *pri = NULL, *sec = NULL; |
| 715 | int status = IX_CRYPTO_ACC_STATUS_SUCCESS; |
| 716 | |
| 717 | if (!ixp) { |
| 718 | printk("ixp: ixp_registration with no arg\n"); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | if (ixp->ixp_ctx_id != -1) { |
| 723 | ixCryptoAccCtxUnregister(ixp->ixp_ctx_id); |
| 724 | ixp->ixp_ctx_id = -1; |
| 725 | } |
| 726 | |
| 727 | if (list_empty(&ixp->ixp_q)) { |
| 728 | printk("ixp: ixp_registration with no Q\n"); |
| 729 | return; |
| 730 | } |
| 731 | |
| 732 | /* |
| 733 | * setup the primary and secondary buffers |
| 734 | */ |
| 735 | q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); |
| 736 | if (q->ixp_q_acrd) { |
| 737 | pri = &ixp->ixp_pri_mbuf; |
| 738 | sec = &ixp->ixp_sec_mbuf; |
| 739 | IX_MBUF_MLEN(pri) = IX_MBUF_PKT_LEN(pri) = 128; |
| 740 | IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); |
| 741 | IX_MBUF_MLEN(sec) = IX_MBUF_PKT_LEN(sec) = 128; |
| 742 | IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); |
| 743 | } |
| 744 | |
| 745 | /* Only need to register if a crypt op or HMAC op */ |
| 746 | if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 || |
| 747 | ixp->ixp_auth_alg == CRYPTO_MD5)) { |
| 748 | status = ixCryptoAccCtxRegister( |
| 749 | &ixp->ixp_ctx, |
| 750 | pri, sec, |
| 751 | ixp_register_cb, |
| 752 | ixp_perform_cb, |
| 753 | &ixp->ixp_ctx_id); |
| 754 | } |
| 755 | else { |
| 756 | /* Otherwise we start processing pending q */ |
| 757 | schedule_work(&ixp->ixp_pending_work); |
| 758 | } |
| 759 | |
| 760 | if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) |
| 761 | return; |
| 762 | |
| 763 | if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) { |
| 764 | printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n"); |
| 765 | ixp_blocked = 1; |
| 766 | /* perhaps we should return EGAIN on queued ops ? */ |
| 767 | return; |
| 768 | } |
| 769 | |
| 770 | printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); |
| 771 | ixp->ixp_ctx_id = -1; |
| 772 | |
| 773 | /* |
| 774 | * everything waiting is toasted |
| 775 | */ |
| 776 | while (!list_empty(&ixp->ixp_q)) { |
| 777 | q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); |
| 778 | list_del(&q->ixp_q_list); |
| 779 | q->ixp_q_crp->crp_etype = ENOENT; |
| 780 | crypto_done(q->ixp_q_crp); |
| 781 | kmem_cache_free(qcache, q); |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
| 786 | static void |
| 787 | ixp_registration_wq(struct work_struct *work) |
| 788 | { |
| 789 | struct ixp_data *ixp = container_of(work, struct ixp_data, |
| 790 | ixp_registration_work); |
| 791 | ixp_registration(ixp); |
| 792 | } |
| 793 | #endif |
| 794 | |
| 795 | /* |
| 796 | * Process a request. |
| 797 | */ |
| 798 | static int |
| 799 | ixp_process(device_t dev, struct cryptop *crp, int hint) |
| 800 | { |
| 801 | struct ixp_data *ixp; |
| 802 | unsigned int lid; |
| 803 | struct ixp_q *q = NULL; |
| 804 | int status; |
| 805 | |
| 806 | dprintk("%s()\n", __FUNCTION__); |
| 807 | |
| 808 | /* Sanity check */ |
| 809 | if (crp == NULL) { |
| 810 | dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); |
| 811 | return EINVAL; |
| 812 | } |
| 813 | |
| 814 | crp->crp_etype = 0; |
| 815 | |
| 816 | if (ixp_blocked) |
| 817 | return ERESTART; |
| 818 | |
| 819 | if (crp->crp_desc == NULL || crp->crp_buf == NULL) { |
| 820 | dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); |
| 821 | crp->crp_etype = EINVAL; |
| 822 | goto done; |
| 823 | } |
| 824 | |
| 825 | /* |
| 826 | * find the session we are using |
| 827 | */ |
| 828 | |
| 829 | lid = crp->crp_sid & 0xffffffff; |
| 830 | if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL || |
| 831 | ixp_sessions[lid] == NULL) { |
| 832 | crp->crp_etype = ENOENT; |
| 833 | dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); |
| 834 | goto done; |
| 835 | } |
| 836 | ixp = ixp_sessions[lid]; |
| 837 | |
| 838 | /* |
| 839 | * setup a new request ready for queuing |
| 840 | */ |
| 841 | q = kmem_cache_alloc(qcache, SLAB_ATOMIC); |
| 842 | if (q == NULL) { |
| 843 | dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__); |
| 844 | crp->crp_etype = ENOMEM; |
| 845 | goto done; |
| 846 | } |
| 847 | /* |
| 848 | * save some cycles by only zeroing the important bits |
| 849 | */ |
| 850 | memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf)); |
| 851 | q->ixp_q_ccrd = NULL; |
| 852 | q->ixp_q_acrd = NULL; |
| 853 | q->ixp_q_crp = crp; |
| 854 | q->ixp_q_data = ixp; |
| 855 | |
| 856 | /* |
| 857 | * point the cipher and auth descriptors appropriately |
| 858 | * check that we have something to do |
| 859 | */ |
| 860 | if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg) |
| 861 | q->ixp_q_ccrd = crp->crp_desc; |
| 862 | else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg) |
| 863 | q->ixp_q_acrd = crp->crp_desc; |
| 864 | else { |
| 865 | crp->crp_etype = ENOENT; |
| 866 | dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); |
| 867 | goto done; |
| 868 | } |
| 869 | if (crp->crp_desc->crd_next) { |
| 870 | if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg) |
| 871 | q->ixp_q_ccrd = crp->crp_desc->crd_next; |
| 872 | else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg) |
| 873 | q->ixp_q_acrd = crp->crp_desc->crd_next; |
| 874 | else { |
| 875 | crp->crp_etype = ENOENT; |
| 876 | dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); |
| 877 | goto done; |
| 878 | } |
| 879 | } |
| 880 | |
| 881 | /* |
| 882 | * If there is a direction change for this context then we mark it as |
| 883 | * unregistered and re-register is for the new direction. This is not |
| 884 | * a very expensive operation and currently only tends to happen when |
| 885 | * user-space application are doing benchmarks |
| 886 | * |
| 887 | * DM - we should be checking for pending requests before unregistering. |
| 888 | */ |
| 889 | if (q->ixp_q_ccrd && ixp->ixp_registered && |
| 890 | ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) { |
| 891 | dprintk("%s - detected direction change on session\n", __FUNCTION__); |
| 892 | ixp->ixp_registered = 0; |
| 893 | } |
| 894 | |
| 895 | /* |
| 896 | * if we are registered, call straight into the perform code |
| 897 | */ |
| 898 | if (ixp->ixp_registered) { |
| 899 | ixp_q_process(q); |
| 900 | return 0; |
| 901 | } |
| 902 | |
| 903 | /* |
| 904 | * the only part of the context not set in newsession is the direction |
| 905 | * dependent parts |
| 906 | */ |
| 907 | if (q->ixp_q_ccrd) { |
| 908 | ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT); |
| 909 | if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) { |
| 910 | ixp->ixp_ctx.operation = q->ixp_q_acrd ? |
| 911 | IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT; |
| 912 | } else { |
| 913 | ixp->ixp_ctx.operation = q->ixp_q_acrd ? |
| 914 | IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT; |
| 915 | } |
| 916 | } else { |
| 917 | /* q->ixp_q_acrd must be set if we are here */ |
| 918 | ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC; |
| 919 | } |
| 920 | |
| 921 | status = list_empty(&ixp->ixp_q); |
| 922 | list_add_tail(&q->ixp_q_list, &ixp->ixp_q); |
| 923 | if (status) |
| 924 | schedule_work(&ixp->ixp_registration_work); |
| 925 | return 0; |
| 926 | |
| 927 | done: |
| 928 | if (q) |
| 929 | kmem_cache_free(qcache, q); |
| 930 | crypto_done(crp); |
| 931 | return 0; |
| 932 | } |
| 933 | |
| 934 | |
| 935 | #ifdef __ixp46X |
| 936 | /* |
| 937 | * key processing support for the ixp465 |
| 938 | */ |
| 939 | |
| 940 | |
| 941 | /* |
| 942 | * copy a BN (LE) into a buffer (BE) an fill out the op appropriately |
| 943 | * assume zeroed and only copy bits that are significant |
| 944 | */ |
| 945 | |
| 946 | static int |
| 947 | ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf) |
| 948 | { |
| 949 | unsigned char *src = (unsigned char *) p->crp_p; |
| 950 | unsigned char *dst; |
| 951 | int len, bits = p->crp_nbits; |
| 952 | |
| 953 | dprintk("%s()\n", __FUNCTION__); |
| 954 | |
| 955 | if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) { |
| 956 | dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__, |
| 957 | bits, MAX_IOP_SIZE * sizeof(UINT32) * 8); |
| 958 | return -1; |
| 959 | } |
| 960 | |
| 961 | len = (bits + 31) / 32; /* the number UINT32's needed */ |
| 962 | |
| 963 | dst = (unsigned char *) &buf[len]; |
| 964 | dst--; |
| 965 | |
| 966 | while (bits > 0) { |
| 967 | *dst-- = *src++; |
| 968 | bits -= 8; |
| 969 | } |
| 970 | |
| 971 | #if 0 /* no need to zero remaining bits as it is done during request alloc */ |
| 972 | while (dst > (unsigned char *) buf) |
| 973 | *dst-- = '\0'; |
| 974 | #endif |
| 975 | |
| 976 | op->pData = buf; |
| 977 | op->dataLen = len; |
| 978 | return 0; |
| 979 | } |
| 980 | |
| 981 | /* |
| 982 | * copy out the result, be as forgiving as we can about small output buffers |
| 983 | */ |
| 984 | |
| 985 | static int |
| 986 | ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf) |
| 987 | { |
| 988 | unsigned char *dst = (unsigned char *) p->crp_p; |
| 989 | unsigned char *src = (unsigned char *) buf; |
| 990 | int len, z, bits = p->crp_nbits; |
| 991 | |
| 992 | dprintk("%s()\n", __FUNCTION__); |
| 993 | |
| 994 | len = op->dataLen * sizeof(UINT32); |
| 995 | |
| 996 | /* skip leading zeroes to be small buffer friendly */ |
| 997 | z = 0; |
| 998 | while (z < len && src[z] == '\0') |
| 999 | z++; |
| 1000 | |
| 1001 | src += len; |
| 1002 | src--; |
| 1003 | len -= z; |
| 1004 | |
| 1005 | while (len > 0 && bits > 0) { |
| 1006 | *dst++ = *src--; |
| 1007 | len--; |
| 1008 | bits -= 8; |
| 1009 | } |
| 1010 | |
| 1011 | while (bits > 0) { |
| 1012 | *dst++ = '\0'; |
| 1013 | bits -= 8; |
| 1014 | } |
| 1015 | |
| 1016 | if (len > 0) { |
| 1017 | dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n", |
| 1018 | __FUNCTION__, len, z, p->crp_nbits / 8); |
| 1019 | return -1; |
| 1020 | } |
| 1021 | |
| 1022 | return 0; |
| 1023 | } |
| 1024 | |
| 1025 | |
| 1026 | /* |
| 1027 | * the parameter offsets for exp_mod |
| 1028 | */ |
| 1029 | |
| 1030 | #define IXP_PARAM_BASE 0 |
| 1031 | #define IXP_PARAM_EXP 1 |
| 1032 | #define IXP_PARAM_MOD 2 |
| 1033 | #define IXP_PARAM_RES 3 |
| 1034 | |
| 1035 | /* |
| 1036 | * key processing complete callback, is also used to start processing |
| 1037 | * by passing a NULL for pResult |
| 1038 | */ |
| 1039 | |
| 1040 | static void |
| 1041 | ixp_kperform_cb( |
| 1042 | IxCryptoAccPkeEauOperation operation, |
| 1043 | IxCryptoAccPkeEauOpResult *pResult, |
| 1044 | BOOL carryOrBorrow, |
| 1045 | IxCryptoAccStatus status) |
| 1046 | { |
| 1047 | struct ixp_pkq *q, *tmp; |
| 1048 | unsigned long flags; |
| 1049 | |
| 1050 | dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult, |
| 1051 | carryOrBorrow, status); |
| 1052 | |
| 1053 | /* handle a completed request */ |
| 1054 | if (pResult) { |
| 1055 | if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) { |
| 1056 | q = ixp_pk_cur; |
| 1057 | if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 1058 | dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status); |
| 1059 | q->pkq_krp->krp_status = ERANGE; /* could do better */ |
| 1060 | } else { |
| 1061 | /* copy out the result */ |
| 1062 | if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES], |
| 1063 | &q->pkq_result, q->pkq_obuf)) |
| 1064 | q->pkq_krp->krp_status = ERANGE; |
| 1065 | } |
| 1066 | crypto_kdone(q->pkq_krp); |
| 1067 | kfree(q); |
| 1068 | ixp_pk_cur = NULL; |
| 1069 | } else |
| 1070 | printk("%s - callback with invalid result pointer\n", __FUNCTION__); |
| 1071 | } |
| 1072 | |
| 1073 | spin_lock_irqsave(&ixp_pkq_lock, flags); |
| 1074 | if (ixp_pk_cur || list_empty(&ixp_pkq)) { |
| 1075 | spin_unlock_irqrestore(&ixp_pkq_lock, flags); |
| 1076 | return; |
| 1077 | } |
| 1078 | |
| 1079 | list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) { |
| 1080 | |
| 1081 | list_del(&q->pkq_list); |
| 1082 | ixp_pk_cur = q; |
| 1083 | |
| 1084 | spin_unlock_irqrestore(&ixp_pkq_lock, flags); |
| 1085 | |
| 1086 | status = ixCryptoAccPkeEauPerform( |
| 1087 | IX_CRYPTO_ACC_OP_EAU_MOD_EXP, |
| 1088 | &q->pkq_op, |
| 1089 | ixp_kperform_cb, |
| 1090 | &q->pkq_result); |
| 1091 | |
| 1092 | if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 1093 | dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__); |
| 1094 | return; /* callback will return here for callback */ |
| 1095 | } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) { |
| 1096 | printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__); |
| 1097 | } else { |
| 1098 | printk("%s() - ixCryptoAccPkeEauPerform failed %d\n", |
| 1099 | __FUNCTION__, status); |
| 1100 | } |
| 1101 | q->pkq_krp->krp_status = ERANGE; /* could do better */ |
| 1102 | crypto_kdone(q->pkq_krp); |
| 1103 | kfree(q); |
| 1104 | spin_lock_irqsave(&ixp_pkq_lock, flags); |
| 1105 | } |
| 1106 | spin_unlock_irqrestore(&ixp_pkq_lock, flags); |
| 1107 | } |
| 1108 | |
| 1109 | |
| 1110 | static int |
| 1111 | ixp_kprocess(device_t dev, struct cryptkop *krp, int hint) |
| 1112 | { |
| 1113 | struct ixp_pkq *q; |
| 1114 | int rc = 0; |
| 1115 | unsigned long flags; |
| 1116 | |
| 1117 | dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__, |
| 1118 | krp->krp_param[IXP_PARAM_BASE].crp_nbits, |
| 1119 | krp->krp_param[IXP_PARAM_EXP].crp_nbits, |
| 1120 | krp->krp_param[IXP_PARAM_MOD].crp_nbits, |
| 1121 | krp->krp_param[IXP_PARAM_RES].crp_nbits); |
| 1122 | |
| 1123 | |
| 1124 | if (krp->krp_op != CRK_MOD_EXP) { |
| 1125 | krp->krp_status = EOPNOTSUPP; |
| 1126 | goto err; |
| 1127 | } |
| 1128 | |
| 1129 | q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); |
| 1130 | if (q == NULL) { |
| 1131 | krp->krp_status = ENOMEM; |
| 1132 | goto err; |
| 1133 | } |
| 1134 | |
| 1135 | /* |
| 1136 | * The PKE engine does not appear to zero the output buffer |
| 1137 | * appropriately, so we need to do it all here. |
| 1138 | */ |
| 1139 | memset(q, 0, sizeof(*q)); |
| 1140 | |
| 1141 | q->pkq_krp = krp; |
| 1142 | INIT_LIST_HEAD(&q->pkq_list); |
| 1143 | |
| 1144 | if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M, |
| 1145 | q->pkq_ibuf0)) |
| 1146 | rc = 1; |
| 1147 | if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP], |
| 1148 | &q->pkq_op.modExpOpr.e, q->pkq_ibuf1)) |
| 1149 | rc = 2; |
| 1150 | if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD], |
| 1151 | &q->pkq_op.modExpOpr.N, q->pkq_ibuf2)) |
| 1152 | rc = 3; |
| 1153 | |
| 1154 | if (rc) { |
| 1155 | kfree(q); |
| 1156 | krp->krp_status = ERANGE; |
| 1157 | goto err; |
| 1158 | } |
| 1159 | |
| 1160 | q->pkq_result.pData = q->pkq_obuf; |
| 1161 | q->pkq_result.dataLen = |
| 1162 | (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32; |
| 1163 | |
| 1164 | spin_lock_irqsave(&ixp_pkq_lock, flags); |
| 1165 | list_add_tail(&q->pkq_list, &ixp_pkq); |
| 1166 | spin_unlock_irqrestore(&ixp_pkq_lock, flags); |
| 1167 | |
| 1168 | if (!ixp_pk_cur) |
| 1169 | ixp_kperform_cb(0, NULL, 0, 0); |
| 1170 | return (0); |
| 1171 | |
| 1172 | err: |
| 1173 | crypto_kdone(krp); |
| 1174 | return (0); |
| 1175 | } |
| 1176 | |
| 1177 | |
| 1178 | |
| 1179 | #ifdef CONFIG_OCF_RANDOMHARVEST |
| 1180 | /* |
| 1181 | * We run the random number generator output through SHA so that it |
| 1182 | * is FIPS compliant. |
| 1183 | */ |
| 1184 | |
| 1185 | static volatile int sha_done = 0; |
| 1186 | static unsigned char sha_digest[20]; |
| 1187 | |
| 1188 | static void |
| 1189 | ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status) |
| 1190 | { |
| 1191 | dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status); |
| 1192 | if (sha_digest != digest) |
| 1193 | printk("digest error\n"); |
| 1194 | if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) |
| 1195 | sha_done = 1; |
| 1196 | else |
| 1197 | sha_done = -status; |
| 1198 | } |
| 1199 | |
| 1200 | static int |
| 1201 | ixp_read_random(void *arg, u_int32_t *buf, int maxwords) |
| 1202 | { |
| 1203 | IxCryptoAccStatus status; |
| 1204 | int i, n, rc; |
| 1205 | |
| 1206 | dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords); |
| 1207 | memset(buf, 0, maxwords * sizeof(*buf)); |
| 1208 | status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf); |
| 1209 | if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 1210 | dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n", |
| 1211 | __FUNCTION__, status); |
| 1212 | return 0; |
| 1213 | } |
| 1214 | |
| 1215 | /* |
| 1216 | * run the random data through SHA to make it look more random |
| 1217 | */ |
| 1218 | |
| 1219 | n = sizeof(sha_digest); /* process digest bytes at a time */ |
| 1220 | |
| 1221 | rc = 0; |
| 1222 | for (i = 0; i < maxwords; i += n / sizeof(*buf)) { |
| 1223 | if ((maxwords - i) * sizeof(*buf) < n) |
| 1224 | n = (maxwords - i) * sizeof(*buf); |
| 1225 | sha_done = 0; |
| 1226 | status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1, |
| 1227 | (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest); |
| 1228 | if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { |
| 1229 | dprintk("ixCryptoAccPkeHashPerform failed %d\n", status); |
| 1230 | return -EIO; |
| 1231 | } |
| 1232 | while (!sha_done) |
| 1233 | schedule(); |
| 1234 | if (sha_done < 0) { |
| 1235 | dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done); |
| 1236 | return 0; |
| 1237 | } |
| 1238 | memcpy(&buf[i], sha_digest, n); |
| 1239 | rc += n / sizeof(*buf);; |
| 1240 | } |
| 1241 | |
| 1242 | return rc; |
| 1243 | } |
| 1244 | #endif /* CONFIG_OCF_RANDOMHARVEST */ |
| 1245 | |
| 1246 | #endif /* __ixp46X */ |
| 1247 | |
| 1248 | |
| 1249 | |
| 1250 | /* |
| 1251 | * our driver startup and shutdown routines |
| 1252 | */ |
| 1253 | |
| 1254 | static int |
| 1255 | ixp_init(void) |
| 1256 | { |
| 1257 | dprintk("%s(%p)\n", __FUNCTION__, ixp_init); |
| 1258 | |
| 1259 | if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS) |
| 1260 | printk("ixCryptoAccInit failed, assuming already initialised!\n"); |
| 1261 | |
| 1262 | qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0, |
| 1263 | SLAB_HWCACHE_ALIGN, NULL |
| 1264 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) |
| 1265 | , NULL |
| 1266 | #endif |
| 1267 | ); |
| 1268 | if (!qcache) { |
| 1269 | printk("failed to create Qcache\n"); |
| 1270 | return -ENOENT; |
| 1271 | } |
| 1272 | |
| 1273 | memset(&ixpdev, 0, sizeof(ixpdev)); |
| 1274 | softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods); |
| 1275 | |
| 1276 | ixp_id = crypto_get_driverid(softc_get_device(&ixpdev), |
| 1277 | CRYPTOCAP_F_HARDWARE); |
| 1278 | if (ixp_id < 0) |
| 1279 | panic("IXP/OCF crypto device cannot initialize!"); |
| 1280 | |
| 1281 | #define REGISTER(alg) \ |
| 1282 | crypto_register(ixp_id,alg,0,0) |
| 1283 | |
| 1284 | REGISTER(CRYPTO_DES_CBC); |
| 1285 | REGISTER(CRYPTO_3DES_CBC); |
| 1286 | REGISTER(CRYPTO_RIJNDAEL128_CBC); |
| 1287 | #ifdef CONFIG_OCF_IXP4XX_SHA1_MD5 |
| 1288 | REGISTER(CRYPTO_MD5); |
| 1289 | REGISTER(CRYPTO_SHA1); |
| 1290 | #endif |
| 1291 | REGISTER(CRYPTO_MD5_HMAC); |
| 1292 | REGISTER(CRYPTO_SHA1_HMAC); |
| 1293 | #undef REGISTER |
| 1294 | |
| 1295 | #ifdef __ixp46X |
| 1296 | spin_lock_init(&ixp_pkq_lock); |
| 1297 | /* |
| 1298 | * we do not enable the go fast options here as they can potentially |
| 1299 | * allow timing based attacks |
| 1300 | * |
| 1301 | * http://www.openssl.org/news/secadv_20030219.txt |
| 1302 | */ |
| 1303 | ixCryptoAccPkeEauExpConfig(0, 0); |
| 1304 | crypto_kregister(ixp_id, CRK_MOD_EXP, 0); |
| 1305 | #ifdef CONFIG_OCF_RANDOMHARVEST |
| 1306 | crypto_rregister(ixp_id, ixp_read_random, NULL); |
| 1307 | #endif |
| 1308 | #endif |
| 1309 | |
| 1310 | return 0; |
| 1311 | } |
| 1312 | |
| 1313 | static void |
| 1314 | ixp_exit(void) |
| 1315 | { |
| 1316 | dprintk("%s()\n", __FUNCTION__); |
| 1317 | crypto_unregister_all(ixp_id); |
| 1318 | ixp_id = -1; |
| 1319 | kmem_cache_destroy(qcache); |
| 1320 | qcache = NULL; |
| 1321 | } |
| 1322 | |
| 1323 | module_init(ixp_init); |
| 1324 | module_exit(ixp_exit); |
| 1325 | |
| 1326 | MODULE_LICENSE("Dual BSD/GPL"); |
| 1327 | MODULE_AUTHOR("David McCullough <dmccullough@cyberguard.com>"); |
| 1328 | MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)"); |
| 1329 | |