/* This is the main crypto function - zero-copy edition */ static int __crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop) { struct scatterlist *src_sg, *dst_sg; struct crypt_op *cop = &kcop->cop; int ret = 0; ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len, kcop->task, kcop->mm, &src_sg, &dst_sg); if (unlikely(ret)) { derr(1, "Error getting user pages. Falling back to non zero copy."); return __crypto_run_std(ses_ptr, cop); } ret = hash_n_crypt(ses_ptr, cop, src_sg, dst_sg, cop->len); release_user_pages(ses_ptr); return ret; }
/* This is the main crypto function - zero-copy edition */ static int __crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop) { struct scatterlist *dst_sg, *auth_sg, *src_sg; struct crypt_auth_op *caop = &kcaop->caop; int ret = 0; if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) { if (unlikely(ses_ptr->cdata.init != 0 && (ses_ptr->cdata.stream == 0 || ses_ptr->cdata.aead != 0))) { dprintk(0, KERN_ERR, "Only stream modes are allowed in SRTP mode (but not AEAD)\n"); return -EINVAL; } ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg); if (unlikely(ret)) { dprintk(1, KERN_ERR, "get_userbuf_srtp(): Error getting user pages.\n"); return ret; } ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, dst_sg, caop->len); release_user_pages(ses_ptr); } else { /* TLS and normal cases. Here auth data are usually small * so we just copy them to a free page, instead of trying * to map them. */ unsigned char* auth_buf = NULL; struct scatterlist tmp; if (unlikely(caop->auth_len > PAGE_SIZE)) { dprintk(1, KERN_ERR, "auth data len is excessive.\n"); return -EINVAL; } auth_buf = (char *)__get_free_page(GFP_KERNEL); if (unlikely(!auth_buf)) { dprintk(1, KERN_ERR, "unable to get a free page.\n"); return -ENOMEM; } if (caop->auth_src && caop->auth_len > 0) { if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) { dprintk(1, KERN_ERR, "unable to copy auth data from userspace.\n"); ret = -EFAULT; goto free_auth_buf; } sg_init_one(&tmp, auth_buf, caop->auth_len); auth_sg = &tmp; } else { auth_sg = NULL; } if (caop->flags & COP_FLAG_AEAD_TLS_TYPE && ses_ptr->cdata.aead == 0) { ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg); if (unlikely(ret)) { dprintk(1, KERN_ERR, "get_userbuf_tls(): Error getting user pages.\n"); goto free_auth_buf; } ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, dst_sg, caop->len); } else { int dst_len; if (unlikely(ses_ptr->cdata.init == 0 || ses_ptr->cdata.stream == 0 || ses_ptr->cdata.aead == 0)) { dprintk(0, KERN_ERR, "Only stream and AEAD ciphers are allowed for authenc\n"); ret = -EINVAL; goto free_auth_buf; } if (caop->op == COP_ENCRYPT) dst_len = caop->len + cryptodev_cipher_get_tag_size(&ses_ptr->cdata); else dst_len = caop->len; ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, dst_len, kcaop->task, kcaop->mm, &src_sg, &dst_sg); if (unlikely(ret)) { dprintk(1, KERN_ERR, "get_userbuf(): Error getting user pages.\n"); goto free_auth_buf; } ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, src_sg, dst_sg, caop->len); } release_user_pages(ses_ptr); free_auth_buf: free_page((unsigned long)auth_buf); } return ret; }