MV_STATUS mvCesaIfAction(MV_CESA_COMMAND *pCmd) { MV_U8 chan = 0, chanIndex = 0; MV_U64 min; if(MV_CESA_CHANNELS > 1) { switch(currCesaPolicy) { case CESA_WEIGHTED_CHAN_POLICY: case CESA_NULL_POLICY: min = chanWeight[0]; for(chan = 1; chan < MV_CESA_CHANNELS; chan++) { if(chanWeight[chan] < min) { min = chanWeight[chan]; chanIndex = chan; } } chanWeight[chanIndex] += pCmd->pSrc->mbufSize; break; case CESA_FLOW_ASSOC_CHAN_POLICY: /* TBD - handle policy */ break; case CESA_SINGLE_CHAN_POLICY: break; default: mvOsPrintf("%s: Error, policy not supported\n", __func__); return MV_ERROR; } /* Check if we need to handle SPLIT case */ if(pCmd->split != MV_CESA_SPLIT_NONE) { if(pCmd->split == MV_CESA_SPLIT_FIRST) splitChanId = chanIndex; else /* MV_CESA_SPLIT_SECOND */ chanIndex = splitChanId; } /* In case of 2 channels or more, update request id */ pCmd->reqId = gReqId; gReqId = ((gReqId+1) % resQueueDepth); } return mvCesaAction(chanIndex, pCmd); }
MV_STATUS mvNfpSecEspProcess(MV_PKT_INFO *pPktInfo, MV_NFP_SEC_SA_ENTRY *pSAEntry) { MV_CESA_COMMAND *pCesaCmd; MV_CESA_MBUF *pCesaMbuf; MV_NFP_SEC_CESA_PRIV *pCesaPriv; MV_STATUS status; MV_IP_HEADER *pIpHdr; MV_BUF_INFO *pBuf; pCesaCmd = &cesaCmdArray[cesaCmdIndx]; pCesaMbuf = &cesaMbufArray[cesaCmdIndx]; cesaCmdIndx++; cesaCmdIndx %= MV_NFP_SEC_Q_SIZE; pCesaPriv = &cesaPrivArray[cesaPrivIndx++]; cesaPrivIndx = cesaPrivIndx % (MV_NFP_SEC_Q_SIZE + MV_NFP_SEC_REQ_Q_SIZE); pCesaPriv->pPktInfo = pPktInfo; pCesaPriv->pSaEntry = pSAEntry; pCesaPriv->pCesaCmd = pCesaCmd; /* * Fix, encrypt/decrypt the IP payload only, --BK 20091027 */ pBuf = pPktInfo->pFrags; pIpHdr = (MV_IP_HEADER *) (pBuf->bufVirtPtr + sizeof(MV_802_3_HEADER)); pBuf->dataSize = MV_16BIT_BE(pIpHdr->totalLength) + sizeof(MV_802_3_HEADER); pBuf->bufVirtPtr += MV_NFP_SEC_ESP_OFFSET; pBuf->bufPhysAddr += MV_NFP_SEC_ESP_OFFSET; pBuf->dataSize -= MV_NFP_SEC_ESP_OFFSET; pBuf->bufAddrShift -= MV_NFP_SEC_ESP_OFFSET; pCesaMbuf->pFrags = pPktInfo->pFrags; pCesaMbuf->numFrags = 1; pCesaMbuf->mbufSize = pBuf->dataSize; pCesaCmd->pReqPrv = (MV_VOID *) pCesaPriv; pCesaCmd->sessionId = pSAEntry->sid; pCesaCmd->pSrc = pCesaMbuf; pCesaCmd->pDst = pCesaMbuf; pCesaCmd->skipFlush = MV_TRUE; /* Assume ESP */ pCesaCmd->cryptoOffset = sizeof(MV_ESP_HEADER) + pSAEntry->ivSize; pCesaCmd->cryptoLength = pBuf->dataSize - (sizeof(MV_ESP_HEADER) + pSAEntry->ivSize + pSAEntry->digestSize); pCesaCmd->ivFromUser = 0; /* relevant for encode only */ pCesaCmd->ivOffset = sizeof(MV_ESP_HEADER); pCesaCmd->macOffset = 0; pCesaCmd->macLength = pBuf->dataSize - pSAEntry->digestSize; pCesaCmd->digestOffset = pBuf->dataSize - pSAEntry->digestSize; /* save original digest in case of decrypt+auth */ if (pSAEntry->secOp == MV_NFP_SEC_DECRYPT) { memcpy(pCesaPriv->orgDigest, (pBuf->bufVirtPtr + pCesaCmd->digestOffset), pSAEntry->digestSize); mvNfpSecInvRange((pBuf->bufVirtPtr + pCesaCmd->digestOffset), pSAEntry->digestSize); } pSAEntry->stats.bytes += pBuf->dataSize; if (pSAEntry->secOp == MV_NFP_SEC_DECRYPT) pSAEntry->stats.decrypt++; else pSAEntry->stats.encrypt++; disable_irq(CESA_IRQ); status = mvCesaAction(pCesaCmd); enable_irq(CESA_IRQ); if (status != MV_OK) { pSAEntry->stats.rejected++; mvOsPrintf("%s: mvCesaAction failed %d\n", __func__, status); } return status; }
/* * Process a request. */ static int cesa_ocf_process(device_t dev, struct cryptop *crp, int hint) { struct cesa_ocf_process *cesa_ocf_cmd = NULL; struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL; MV_CESA_COMMAND *cesa_cmd; struct cryptodesc *crd; struct cesa_ocf_data *cesa_ocf_cur_ses; int sid = 0, temp_len = 0, i; int encrypt = 0, decrypt = 0, auth = 0; int status; struct sk_buff *skb = NULL; struct uio *uiop = NULL; unsigned char *ivp; MV_BUF_INFO *p_buf_info; MV_CESA_MBUF *p_mbuf_info; unsigned long flags; dprintk("%s()\n", __FUNCTION__); if( cesaReqResources <= 1 ) { dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__); return ERESTART; } #ifdef RT_DEBUG /* Sanity check */ if (crp == NULL) { printk("%s,%d: EINVAL\n", __FILE__, __LINE__); return EINVAL; } if (crp->crp_desc == NULL || crp->crp_buf == NULL ) { printk("%s,%d: EINVAL\n", __FILE__, __LINE__); crp->crp_etype = EINVAL; return EINVAL; } sid = crp->crp_sid & 0xffffffff; if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) { crp->crp_etype = ENOENT; printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid); return EINVAL; } #endif sid = crp->crp_sid & 0xffffffff; crp->crp_etype = 0; cesa_ocf_cur_ses = cesa_ocf_sessions[sid]; #ifdef RT_DEBUG if(ocf_check_action(crp, cesa_ocf_cur_ses)){ goto p_error; } #endif /* malloc a new cesa process */ cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); if (cesa_ocf_cmd == NULL) { printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); goto p_error; } memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process)); /* init cesa_process */ cesa_ocf_cmd->crp = crp; /* always call callback */ cesa_ocf_cmd->need_cb = 1; /* init cesa_cmd for usage of the HALs */ cesa_cmd = &cesa_ocf_cmd->cesa_cmd; cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd; cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */ /* prepare src buffer */ /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */ /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */ /* from skip to crd_len. */ p_buf_info = cesa_ocf_cmd->cesa_bufs; p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf; p_buf_info += 2; /* save 2 first buffers for IV and digest - we won't append them to the end since, they might be places in an unaligned addresses. */ p_mbuf_info->pFrags = p_buf_info; temp_len = 0; /* handle SKB */ if (crp->crp_flags & CRYPTO_F_SKBUF) { dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__); skb = (struct sk_buff *) crp->crp_buf; if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) { printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags); goto p_error; } p_mbuf_info->mbufSize = skb->len; temp_len = skb->len; /* first skb fragment */ p_buf_info->bufSize = skb_headlen(skb); p_buf_info->bufVirtPtr = skb->data; p_buf_info++; /* now handle all other skb fragments */ for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; p_buf_info->bufSize = frag->size; p_buf_info->bufVirtPtr = page_address(FRAG_PAGE(frag->page)) + frag->page_offset; p_buf_info++; } p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1; } /* handle UIO */ else if(crp->crp_flags & CRYPTO_F_IOV) { dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__); uiop = (struct uio *) crp->crp_buf; if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) { printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt); goto p_error; } p_mbuf_info->mbufSize = crp->crp_ilen; p_mbuf_info->numFrags = uiop->uio_iovcnt; for(i = 0; i < uiop->uio_iovcnt; i++) { p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base; p_buf_info->bufSize = uiop->uio_iov[i].iov_len; temp_len += p_buf_info->bufSize; dprintk("%s,%d: buf %x-> addr %x, size %x \n" , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize); p_buf_info++; } } /* handle CONTIG */ else { dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__); p_mbuf_info->numFrags = 1; p_mbuf_info->mbufSize = crp->crp_ilen; p_buf_info->bufVirtPtr = crp->crp_buf; p_buf_info->bufSize = crp->crp_ilen; temp_len = crp->crp_ilen; p_buf_info++; } /* Support up to 64K why? cause! */ if(crp->crp_ilen > 64*1024) { printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen); goto p_error; } if( temp_len != crp->crp_ilen ) { printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen); } cesa_cmd->pSrc = p_mbuf_info; cesa_cmd->pDst = p_mbuf_info; /* restore p_buf_info to point to first available buf */ p_buf_info = cesa_ocf_cmd->cesa_bufs; p_buf_info += 1; /* Go through crypto descriptors, processing as we go */ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { /* Encryption /Decryption */ if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) { dprintk("%s,%d: cipher", __FILE__, __LINE__); cesa_cmd->cryptoOffset = crd->crd_skip; cesa_cmd->cryptoLength = crd->crd_len; if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ dprintk(" encrypt \n"); encrypt++; /* handle IV */ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */ dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject); cesa_cmd->ivFromUser = 1; ivp = crd->crd_iv; /* * do we have to copy the IV back to the buffer ? */ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__); cesa_cmd->ivOffset = crd->crd_inject; crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, cesa_ocf_cur_ses->ivlen, ivp); } else { dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__); p_mbuf_info->numFrags++; p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; p_mbuf_info->pFrags = p_buf_info; p_buf_info->bufVirtPtr = ivp; p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; p_buf_info--; /* offsets */ cesa_cmd->ivOffset = 0; cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; if(auth) { cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; } } } else { /* random IV */ dprintk("%s,%d: random IV \n", __FILE__, __LINE__); cesa_cmd->ivFromUser = 0; /* * do we have to copy the IV back to the buffer ? */ /* in this mode the HAL will always copy the IV */ /* given by the session to the ivOffset */ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { cesa_cmd->ivOffset = crd->crd_inject; } else { /* if IV isn't copy, then how will the user know which IV did we use??? */ printk("%s,%d: EINVAL\n", __FILE__, __LINE__); goto p_error; } } } else { /* decrypt */ dprintk(" decrypt \n"); decrypt++; cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt; /* handle IV */ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__); /* append the IV buf to the mbuf */ cesa_cmd->ivFromUser = 1; p_mbuf_info->numFrags++; p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; p_mbuf_info->pFrags = p_buf_info; p_buf_info->bufVirtPtr = crd->crd_iv; p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; p_buf_info--; /* offsets */ cesa_cmd->ivOffset = 0; cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; if(auth) { cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; } } else { dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__); cesa_cmd->ivFromUser = 0; cesa_cmd->ivOffset = crd->crd_inject; } } } /* Authentication */ else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) { dprintk("%s,%d: Authentication \n", __FILE__, __LINE__); auth++; cesa_cmd->macOffset = crd->crd_skip; cesa_cmd->macLength = crd->crd_len; /* digest + mac */ cesa_cmd->digestOffset = crd->crd_inject; } else { printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__); goto p_error; } } dprintk("\n"); dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__); dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset); dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength); dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength); dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset); if(debug) { mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize); } /* send action to HAL */ spin_lock_irqsave(&cesa_lock, flags); status = mvCesaAction(cesa_cmd); spin_unlock_irqrestore(&cesa_lock, flags); /* action not allowed */ if(status == MV_NOT_ALLOWED) { #ifdef CESA_OCF_SPLIT /* if both encrypt and auth try to split */ if(auth && (encrypt || decrypt)) { MV_CESA_COMMAND *cesa_cmd_wa; /* malloc a new cesa process and init it */ cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); if (cesa_ocf_cmd_wa == NULL) { printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); goto p_error; } memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process)); cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd; cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa; cesa_ocf_cmd_wa->need_cb = 0; /* break requests to two operation, first operation completion won't call callback */ if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) { cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; } else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) { cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; } else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) { cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; } else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){ cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; } else { printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__); goto p_error; } /* send the 2 actions to the HAL */ spin_lock_irqsave(&cesa_lock, flags); status = mvCesaAction(cesa_cmd_wa); spin_unlock_irqrestore(&cesa_lock, flags); if((status != MV_NO_MORE) && (status != MV_OK)) { printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); goto p_error; } spin_lock_irqsave(&cesa_lock, flags); status = mvCesaAction(cesa_cmd); spin_unlock_irqrestore(&cesa_lock, flags); } /* action not allowed and can't split */ else #endif { goto p_error; } } /* Hal Q is full, send again. This should never happen */ if(status == MV_NO_RESOURCE) { printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__); if(cesa_ocf_cmd) kfree(cesa_ocf_cmd); if(cesa_ocf_cmd_wa) kfree(cesa_ocf_cmd_wa); return ERESTART; } else if((status != MV_NO_MORE) && (status != MV_OK)) { printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); goto p_error; } #ifdef CESA_OCF_POLLING cesa_interrupt_polling(); #endif cesaTestTraceAdd(5); return 0; p_error: crp->crp_etype = EINVAL; if(cesa_ocf_cmd) kfree(cesa_ocf_cmd); if(cesa_ocf_cmd_wa) kfree(cesa_ocf_cmd_wa); return EINVAL; }