Files
2026-07-30 11:19:44 +05:30

403 lines
12 KiB
C

/****************************************************************************
* sec2_dpd.c -- Code to construct a packet descriptor for SEC2 Driver
****************************************************************************
* Copyright (c) Certicom Corp. 1996-2002. All rights reserved
* Copyright (c) 2003-2005 Freescale Semiconductor
* All Rights Reserved. Proprietary and Confidential.
*
* NOTICE: The information contained in this file is proprietary
* to Freescale Semiconductor, and is being made available to
* Freescale's customers under strict license agreements.
* Use or disclosure of this information is permissible only
* under the terms of the existing license agreement.
***************************************************************************/
/*
* Revision History:
* 1.0 Aug 24,2003 dgs - adapted from the final version of mpc18x
* May 26,2004 sec - add support for scatter pointers
* 1.1.0 Nov 16,2004 sec - incorporate linux changes from prior versions
* 1.1.1 Dec 16,2004 sec - clean up prototypes and warnings
* 1.2 Jan 27,2005 sec - bugfix in DPD dumper
*/
#include "Sec2Driver.h"
#include "Sec2Descriptors.h"
#include "sec2_dpd_Table.h"
static int VerifyRequest(void *request, DPD_DETAILS_ENTRY *pDesc);
static DPD_DETAILS_ENTRY *GetRequestDescEntry(unsigned long opId);
/* Build a SEC2-channel-compatible fragment map from a generic one */
/* inList: external linked list */
/* ptrEnt: will become head of compatible list we'll construct */
/* */
int MapScatterFragments(unsigned long inList,
unsigned long *ptrEnt)
{
int i, listSiz;
EXT_SCATTER_ELEMENT *inElem;
SCATTER_ELEMENT *outList;
inElem = (EXT_SCATTER_ELEMENT *)inList;
/* How many elements to alloc? */
listSiz = 0;
while (inElem != NULL)
{
listSiz++;
inElem = inElem->next;
}
SEC2Dump(DBGTXT_SETRQ, ("MapScatterFragments(): list 0x%08lx has %d fragments\n", inList, listSiz));
/* Allocate a chunk off the driver's available heap */
outList = malloc(sizeof(SCATTER_ELEMENT) * listSiz);
if (outList == NULL)
return(SEC2_FRAGMENT_POOL_EXHAUSTED);
/* Stuff allocated chunk with caller's info */
i = 0;
inElem = (EXT_SCATTER_ELEMENT *)inList;
while (inElem != NULL)
{
outList[i].segAddr = (void *)__vpa((unsigned long)inElem->fragment);
outList[i].segLen = (unsigned short)inElem->size;
outList[i].linkStat = 0;
inElem = inElem->next;
SEC2Dump(DBGTXT_SETRQ,
("MapScatterFragments(): new fragment 0x%08x, %d bytes\n",
(unsigned)outList[i].segAddr,
outList[i].segLen));
i++;
}
/* once done, set the "return" bit in the last element */
outList[i - 1].linkStat |= SEGLIST_RETURN;
*ptrEnt = __vpa((unsigned long)outList);
return(SEC2_SUCCESS);
}
/* Free a SEC2-hardware-compatible fragment chain. antithesis of MapScatterFragments */
/* Should be called upon as part of a channel interrupt cleanup process */
void UnmapScatterFragments(unsigned long *ptrEnt)
{
/* free((void *)ChannelAssignments[channel].Dpds[i]->fld[j].ptr); */
}
/*
* Convert driver-native request structure to DPD and insert
*/
int RequestToDpd(register GENERIC_REQ *pReq, register int channel)
{
#define DPDPTR (ChannelAssignments[channel].Dpds[dpdCount])
register DPD_DETAILS_ENTRY *pDesc;
register unsigned long opId;
register int i, status;
register int dpdCount;
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): req @0x%08x ch%d\n", (unsigned)pReq, channel+1));
if (pReq == NULL)
return SEC2_NULL_REQUEST;
dpdCount = 0;
/* process request(s) */
/* do {stuff} while pReq points to real request */
do
{
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): get entry for opId 0x%08lx\n", pReq->opId));
pDesc = GetRequestDescEntry (pReq->opId);
if (pDesc == NULL)
return SEC2_INVALID_OPERATION_ID;
/* Validate the contents of the request */
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): VerifyRequest(0x%08x, 0x%08x)\n", (unsigned)pReq, (unsigned)pDesc));
status = VerifyRequest(pReq, pDesc);
if (status != SEC2_SUCCESS)
return status;
/* If there are insufficient DPDs save the current request
list entry and offset. Indicate that the request is "chunked"
*/
if (dpdCount >= MAX_DPDS)
return (SEC2_INSUFFICIENT_REQS);
/*
* We have sufficient resources (DPD slots) to process this request.
* Initialize a DPD and link the prior DPD to this one (if it is not the first)
*/
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): clear DPD 0x%08x\n", (unsigned)DPDPTR));
memset(DPDPTR, 0x00, sizeof(DPD));
/* fill in the dpd header */
opId = pReq->opId;
DPDPTR->header = pDesc->hdrDesc[1*(opId & DESC_NUM_MASK)];
/* For each field in a request: */
for (i = 0; i < NUM_DPD_FLDS && pDesc->fld[i].txt != NULL; i++)
{
if (*(long *)pDesc->fld[i].txt == *(long *)"NIL") {
DPDPTR->fld[i].ptr = 0;
DPDPTR->fld[i].len = 0;
}
else
{
/* deal with basic pointer */
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): converting entry %d->0x%08x\n", i, *(unsigned int *)((unsigned int)pReq + pDesc->fld[i].ptrOffset1st)));
/* if offset AND caller specfied non-NULL pointer, assign/convert that pointer */
if ((pDesc->fld[i].ptrOffset1st != 0) &&
*(unsigned int *)((unsigned int)pReq + pDesc->fld[i].ptrOffset1st))
DPDPTR->fld[i].ptr = __vpa(*(unsigned int *) ((unsigned int)pReq + pDesc->fld[i].ptrOffset1st));
/* if scatter pointer, deal with special case */
if (pReq->scatterBufs & (0x01 << i))
{
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): pointer word %d is scattered\n", i+1));
/* this should be linked list to fragment map, do conversion */
status = MapScatterFragments(*(unsigned int *)((unsigned int)pReq + pDesc->fld[i].ptrOffset1st),
&(DPDPTR->fld[i].ptr));
if (status != SEC2_SUCCESS) /* map failed? */
return(status);
}
/* deal with length */
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): set length = %d\n", *(unsigned int *)((unsigned int)pReq + pDesc->fld[i].lenOffset1st)));
DPDPTR->fld[i].len = *(unsigned int *) ((unsigned int)pReq + pDesc->fld[i].lenOffset1st);
DPDPTR->fld[i].len <<= 16;
SEC2Dump(DBGTXT_SETRQ, ("RequestToDpd(): set offset= %d\n", *(unsigned int *)((unsigned int)pReq + pDesc->fld[i].extOffset)));
if (pDesc->fld[i].extOffset != 0)
DPDPTR->fld[i].len |= *(unsigned int *) ((unsigned int)pReq + pDesc->fld[i].extOffset) << 8;
if (pReq->scatterBufs & (0x01 << i))
DPDPTR->fld[i].len |= PTRTYPE_JBIT; /* set scatter flag bit */
}
}
#ifdef DBG
/* If DPD dump requested, show this packet descriptor content */
if (SEC2DebugLevel | DBGTXT_DPDSHOW) {
SEC2Dump(DBGTXT_DPDSHOW,
("DPD header = 0x%08lx\n", DPDPTR->header));
SEC2Dump(DBGTXT_DPDSHOW,
("Primary EU/Mode 0x%02lx:%02lx, ",
(DPDPTR->header & 0xf0000000) >> 28,
(DPDPTR->header & 0x0ff00000) >> 20));
SEC2Dump(DBGTXT_DPDSHOW,
("Secondary EU/Mode 0x%02lx:%02lx, ",
(DPDPTR->header & 0x000f0000) >> 16,
(DPDPTR->header & 0x0000ff00) >> 8));
SEC2Dump(DBGTXT_DPDSHOW,
("Type 0x%02lx, ",
(DPDPTR->header & 0x000000f8) >> 3));
if (DPDPTR->header & 0x00000002)
SEC2Dump(DBGTXT_DPDSHOW, ("Inbound, "));
else
SEC2Dump(DBGTXT_DPDSHOW, ("Outbound, "));
if (DPDPTR->header & 0x00000001)
SEC2Dump(DBGTXT_DPDSHOW, ("Done\n"));
else
SEC2Dump(DBGTXT_DPDSHOW, ("\n"));
for (i = 0; i < NUM_DPD_FLDS; i++)
SEC2Dump(DBGTXT_DPDSHOW,
("DPD ptr:len/ext p%d = 0x%08lx:%08lx\n",
i,
DPDPTR->fld[i].ptr,
DPDPTR->fld[i].len));
} /* if (DPD SHOW) */
#endif
/* Move onto the next block
*/
pReq = (GENERIC_REQ *)pReq->nextReq;
dpdCount++;
} while (pReq != NULL); /* End while (request != NULL) */
return SEC2_SUCCESS;
} /* end of RequestToDpd */
/*
* Validate request content
*/
int VerifyRequest(register void *request, register DPD_DETAILS_ENTRY *pDesc)
{
register int i;
register unsigned long len;
/* register unsigned long addr; */
for (i = 0; i < NUM_DPD_FLDS && pDesc->fld[i].txt != NULL; i++)
{
/* A NULL pointer to a size checking function means "don't bother checking" */
if (pDesc->fld[i].pFncSize != NULL)
{
len = *(unsigned int *)((unsigned int)request + pDesc->fld[i].lenOffset1st);
if (!pDesc->fld[i].pFncSize(len))
{
SEC2Dump(DBGTXT_SETRQ,
("VerifyRequest->fld(%s) Invalid Length=%ld\n",
pDesc->fld[i].txt, len));
return SEC2_INVALID_LENGTH;
}
}
/* check Extent Length < 128 */
if (pDesc->fld[i].extOffset != 0)
{
len = *(unsigned int *)((unsigned int)request + pDesc->fld[i].extOffset);
if (len >= 128)
return SEC2_INVALID_LENGTH;
}
}
return SEC2_SUCCESS;
}
/* Scan the DPDDetails table for a particular opId value. Return a pointer
to the entry if it is found, NULL otherwise
*/
DPD_DETAILS_ENTRY *GetRequestDescEntry(unsigned long opId)
{
int i = 0;
opId &= DESC_TYPE_MASK;
while (DpdDetails[i].txt != NULL && DpdDetails[i].opId != opId) i++;
return(DpdDetails[i].opId == 0 ? NULL : &DpdDetails[i]);
}
/* The following Chk???() routines and the FitInBlock() routine are used
to verify that the length of a data area is consistent with a request type.
They are supplied as pointers to functions in the DPDDetails table
*/
BOOLEAN ChkDesIvLen(unsigned long len)
{
return len != 0 && len != DES_BLOCK ? FALSE : TRUE;
}
BOOLEAN ChkDesKeyLen(unsigned long len)
{
return len != DES_BLOCK && len != (2*DES_BLOCK) && len != (3*DES_BLOCK) ? FALSE : TRUE;
}
BOOLEAN ChkDesStaticDataLen(unsigned long len)
{
return (len & 0x7) != 0 ? FALSE : TRUE;
}
BOOLEAN ChkDesDataLen(unsigned long len)
{
return (len & 0x7) != 0 ? FALSE : TRUE;
}
BOOLEAN ChkDesCtxLen(unsigned long len)
{
return len != 0 && len != DES_BLOCK != 0 ? FALSE : TRUE;
}
BOOLEAN ChkAesKeyLen(unsigned long len)
{
return len != 16 && len != 24 && len != 32 ? FALSE : TRUE;
}
BOOLEAN ChkAesIvLen(unsigned long len)
{
return len != 0 && len != 16 ? FALSE : TRUE;
}
BOOLEAN ChkArcKeyLen(unsigned long len)
{
return len < ARC4_MIN_KEYBYTES || len > ARC4_MAX_KEYBYTES ? FALSE : TRUE;
}
BOOLEAN ChkArcCtxLen(unsigned long len)
{
return len != ARC4_CONTEXTBYTES ? FALSE : TRUE;
}
BOOLEAN ChkOptionalArcCtxLen(unsigned long len)
{
return len != ARC4_CONTEXTBYTES && len != 0 ? FALSE : TRUE;
}
BOOLEAN ChkEccLen(unsigned long len)
{
return len > 64 ? FALSE : TRUE;
}
BOOLEAN FitInBlock(unsigned long len)
{
return len > BlockSize ? FALSE : TRUE;
}
BOOLEAN ChkCcmpKeyLen(unsigned long len)
{
return len != 0 && len != 16 ? FALSE : TRUE;
}