/** * VpHalHbiRead(): Sends a command, and receives up to 256 data words over the * HBI. * * Accepts a uint16 HBI command which is little-endian or big-endian, depending * on the host architecture. Command words on the HBI bus are always big- * endian. This function is responsible for byte-swapping the command word, if * required. * * Retrieves an array of uint16 data words. No byte-swapping is necessary on * data words in this function. Instead, the HBI bus can be configured in * VpHalHbiInit() to match the endianness of the host platform. * * Params: * uint8 deviceId: Device Id (chip select ID) * uint8 numwords: the number of words to receive, minus 1 * uint16p data: where to put them * * Returns: * TRUE on success, FALSE on failure */ uint8 VpHalHbiRead( VpDeviceIdType deviceId, uint16 cmd, uint8 numwords, uint16p data) { uint8 i; uint16 cmdSwapped = MV_16BIT_BE(cmd); uint16p pReadBuff = &readBuff[0]; if((numwords + 1) > HBI_MAX_DATA_LEN) { mvOsPrintf("%s: Error, HBI data length too big(%u)\n", __FUNCTION__, (numwords + 1)); return FALSE; } DBG("%s: READ(cmd-0x%x), (size-%d bytes)\n", __FUNCTION__, cmd, HBI_DATA_BYTES(numwords)); mvSysTdmSpiRead(deviceId, (uint8p)&cmdSwapped, HBI_CMD_BYTES, (uint8p)pReadBuff, HBI_DATA_BYTES(numwords)); for(i = 0;i < (numwords + 1); i++) data[i] = MV_16BIT_BE(pReadBuff[i]); return TRUE; } /* VpHalHbiRead() */
INLINE MV_VOID mvNfpSecBuildIPTunnel(MV_PKT_INFO *pPktInfo, MV_NFP_SEC_SA_ENTRY *pSAEntry) { MV_IP_HEADER *pIpHdr, *pIntIpHdr; MV_U16 newIpTotalLength; newIpTotalLength = pPktInfo->pFrags[0].dataSize - sizeof(MV_802_3_HEADER); pIpHdr = (MV_IP_HEADER *) (pPktInfo->pFrags[0].bufVirtPtr + sizeof(MV_802_3_HEADER)); pIntIpHdr = (MV_IP_HEADER *) ((MV_U8 *) (pIpHdr) + sizeof(MV_IP_HEADER) + sizeof(MV_ESP_HEADER) + pSAEntry->ivSize); /* TBD - review below settings in RFC */ pIpHdr->version = 0x45; pIpHdr->tos = 0; pIpHdr->checksum = 0; pIpHdr->totalLength = MV_16BIT_BE(newIpTotalLength); pIpHdr->identifier = 0; pIpHdr->fragmentCtrl = 0; pIpHdr->ttl = pIntIpHdr->ttl - 1; pIpHdr->protocol = MV_IP_PROTO_ESP; pIpHdr->srcIP = pSAEntry->tunnelHdr.sIp; pIpHdr->dstIP = pSAEntry->tunnelHdr.dIp; pPktInfo->status = ETH_TX_IP_NO_FRAG | ETH_TX_GENERATE_IP_CHKSUM_MASK | (0x5 << ETH_TX_IP_HEADER_LEN_OFFSET); return; }
/* Print a NFP NAT Rule */ void mvFpNatRulePrint(const MV_FP_NAT_RULE *rule) { /* Note: some of the fields in the NAT rule may contain invalid values */ mvOsPrintf("Original packet: "); mvOsPrintf("SIP="); mvDebugPrintIpAddr(MV_32BIT_BE(rule->srcIp)), mvOsPrintf(", DIP="); mvDebugPrintIpAddr(MV_32BIT_BE(rule->dstIp)), mvOsPrintf(", SPort=%d", MV_16BIT_BE(rule->srcPort)); mvOsPrintf(", DPort=%d", MV_16BIT_BE(rule->dstPort)); mvOsPrintf("\nNAT Info: "); mvOsPrintf("count=%u, flags=0x%x", rule->new_count, rule->flags); mvOsPrintf(", newIP="); mvDebugPrintIpAddr(MV_32BIT_BE(rule->newIp)); mvOsPrintf(", newPort=%d", MV_16BIT_BE(rule->newPort)); mvOsPrintf("\n"); }
/** * VpHalHbiCmd(): Sends a command word over the HBI, with no data words. * * Accepts a uint16 HBI command which is little-endian or big-endian, * depending on the host architecture. Command words on the HBI bus are always * big-endian. This function is responsible for byte-swapping if required. * * Params: * uint8 deviceId: Device Id (chip select ID) * uint16 cmd: the command word to send * * Returns: * TRUE on success, FALSE on failure */ uint8 VpHalHbiCmd( VpDeviceIdType deviceId, uint16 cmd) { uint16 cmdSwapped = MV_16BIT_BE(cmd); DBG("%s: WRITE(cmd-0x%x)\n", __FUNCTION__, cmd); mvSysTdmSpiWrite(deviceId, (uint8p)&cmdSwapped, HBI_CMD_BYTES, NULL, 0); return TRUE; } /* VpHalHbiCmd() */
/* Delete a specified NAT rule from the SNAT + DNAT table */ MV_STATUS mvFpNatRuleDelete(MV_FP_NAT_RULE *natRule) { MV_U32 hash, hash_tr; MV_FP_NAT_RULE *currRule, *prevRule; natRuleDeleteCount++; hash = mv_jhash_3words(natRule->dstIp, natRule->srcIp, (MV_U32)((natRule->dstPort << 16) | natRule->srcPort), (MV_U32)((fp_ip_jhash_iv << 8) | natRule->proto)); hash_tr = hash & (natRuleDbSize - 1); prevRule = NULL; for (currRule = natRuleDb[hash_tr].natRuleChain; currRule != NULL; prevRule = currRule, currRule = currRule->next) { if (currRule->srcIp == natRule->srcIp && currRule->dstIp == natRule->dstIp && currRule->srcPort == natRule->srcPort && currRule->dstPort == natRule->dstPort && currRule->proto == natRule->proto ) { if (prevRule == NULL) natRuleDb[hash_tr].natRuleChain = currRule->next; else prevRule->next = currRule->next; #ifdef MV_FP_DEBUG mvOsPrintf("DelNAT_%03u: DIP=0x%08x, SIP=0x%08x, proto=%d, DPort=%d, SPort=%d, hash=0x%04x\n", natRuleDeleteCount, currRule->dstIp, currRule->srcIp, currRule->proto, MV_16BIT_BE(currRule->dstPort), MV_16BIT_BE(currRule->srcPort), hash_tr); #endif mvOsFree(currRule); return MV_OK; } } return MV_NOT_FOUND; }
mvOsMemset(nat_hash, 0, bytes); mvOsPrintf("NFP (nat) init %d entries, %d bytes\n", NFP_NAT_HASH_SIZE, bytes); return MV_OK; } static MV_VOID mvNfpNatRulePrint(NFP_RULE_NAT *nat) { mvOsPrintf(MV_IPQUAD_FMT":%d" "->"MV_IPQUAD_FMT":%d" " %-2d " "%s:"MV_IPQUAD_FMT" " "age=%x (%p)\n", MV_IPQUAD(nat->sip), MV_16BIT_BE(nat->ports & 0xFFFF), MV_IPQUAD(nat->dip), MV_16BIT_BE(nat->ports >> 16), nat->proto, nat->flags & NFP_F_DNAT ? "DNAT" : "SNAT", MV_IPQUAD(nat->nip), nat->age, nat); } static INLINE MV_U32 mvNfpNatHash(NFP_RULE_NAT *nat) { int family = MV_INET; return mv_jhash_2addr(family, (const MV_U8 *)&nat->sip, (const MV_U8 *)&nat->dip, nat->ports | nat->proto, mgr_rule_jhash_iv); } static INLINE NFP_RULE_NAT *mvNfpNatLookup(NFP_RULE_NAT *nat2) {
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; }
/* Set a NAT rule: create a new rule or update an existing rule in the SNAT + DNAT table */ MV_STATUS mvFpNatRuleSet(MV_FP_NAT_RULE *pSetRule) { int depth = 0; MV_U32 hash, hash_tr; MV_FP_NAT_RULE *pNatRule, *pNewRule; hash = mv_jhash_3words(pSetRule->dstIp, pSetRule->srcIp, (MV_U32)((pSetRule->dstPort << 16) | pSetRule->srcPort), (MV_U32)((fp_ip_jhash_iv << 8) | pSetRule->proto)); hash_tr = hash & (natRuleDbSize - 1); pNatRule = natRuleDb[hash_tr].natRuleChain; while(pNatRule) { /* look for a matching rule */ if( (pNatRule->dstIp == pSetRule->dstIp) && (pNatRule->srcIp == pSetRule->srcIp) && (pNatRule->proto == pSetRule->proto) && (pNatRule->dstPort == pSetRule->dstPort) && (pNatRule->srcPort == pSetRule->srcPort) ) { /* update rule */ mvFpNatRuleUpdate(pNatRule, pSetRule); natRuleUpdateCount++; #ifdef MV_FP_DEBUG mvOsPrintf("UpdNAT_%03u: DIP=0x%08x, SIP=0x%08x, proto=%d, DPort=%d, SPort=%d, hash=0x%04x, flags=0x%02x\n", natRuleUpdateCount, pNatRule->dstIp, pNatRule->srcIp, pNatRule->proto, MV_16BIT_BE(pNatRule->dstPort), MV_16BIT_BE(pNatRule->srcPort), hash_tr, pNatRule->flags); #endif return MV_OK; } pNatRule = pNatRule->next; } /* Allocate new entry */ pNewRule = mvOsMalloc(sizeof(MV_FP_NAT_RULE)); if(pNewRule == NULL) { mvOsPrintf("mvFpNatRuleSet: Can't allocate new rule\n"); return MV_FAIL; } memcpy(pNewRule, pSetRule, sizeof(*pNewRule)); pNewRule->next = NULL; if(natRuleDb[hash_tr].natRuleChain == NULL) { natRuleDb[hash_tr].natRuleChain = pNewRule; } else { pNatRule = natRuleDb[hash_tr].natRuleChain; while (pNatRule->next != NULL) { depth++; pNatRule = pNatRule->next; } pNatRule->next = pNewRule; } if(depth > natHashMaxDepth) natHashMaxDepth = depth; natRuleSetCount++; #ifdef MV_FP_DEBUG mvOsPrintf("SetNAT_%03u: DIP=0x%08x, SIP=0x%08x, proto=%d, DPort=%d, SPort=%d, hash=0x%04x, flags=0x%02x\n", natRuleSetCount, pNewRule->dstIp, pNewRule->srcIp, pNewRule->proto, MV_16BIT_BE(pNewRule->dstPort), MV_16BIT_BE(pNewRule->srcPort), hash_tr, pNewRule->flags); #endif return MV_OK; }