Esempio n. 1
0
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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/*
 * 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;
}