mirror of
https://gitlab.com/padavan-ng/padavan-ng.git
synced 2024-02-13 08:33:30 +08:00
527 lines
10 KiB
C
527 lines
10 KiB
C
/*
|
|
Module Name:
|
|
|
|
ac_policy.c
|
|
|
|
Abstract:
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- ---------- ----------------------------------------------
|
|
Name Date Modification logs
|
|
Steven Liu 2007-01-24 Initial version
|
|
*/
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/list.h>
|
|
|
|
#include "util.h"
|
|
#include "ac_policy.h"
|
|
#include "frame_engine.h"
|
|
|
|
#if defined (CONFIG_RA_HW_NAT_IPV6)
|
|
extern int ipv6_offload;
|
|
#endif
|
|
|
|
static AcPlcyNode AcPlcyList = {.List = LIST_HEAD_INIT(AcPlcyList.List) };
|
|
static char AcFreeList[8];
|
|
|
|
void SyncAcTbl(void)
|
|
{
|
|
struct list_head *pos = NULL, *tmp;
|
|
AcPlcyNode *node = NULL;
|
|
int PreRuleFound = 0, PostRuleFound = 0;
|
|
|
|
PpeSetPreAcEbl(0);
|
|
PpeSetPostAcEbl(0);
|
|
|
|
list_for_each_safe(pos, tmp, &AcPlcyList.List) {
|
|
node = list_entry(pos, AcPlcyNode, List);
|
|
|
|
switch (node->RuleType) {
|
|
case AC_MAC_GROUP:
|
|
AcInsMac(node);
|
|
break;
|
|
case AC_IP_GROUP:
|
|
AcInsIp(node);
|
|
break;
|
|
case AC_VLAN_GROUP:
|
|
AcInsVlan(node);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (node->Type == PRE_AC) {
|
|
PreRuleFound = 1;
|
|
} else {
|
|
PostRuleFound = 1;
|
|
}
|
|
|
|
}
|
|
|
|
if (PreRuleFound) {
|
|
PpeSetPreAcEbl(1);
|
|
}
|
|
if (PostRuleFound) {
|
|
PpeSetPostAcEbl(1);
|
|
}
|
|
}
|
|
|
|
AcPlcyNode *AcExistNode(AcPlcyNode * NewNode)
|
|
{
|
|
struct list_head *pos = NULL, *tmp;
|
|
AcPlcyNode *node = NULL;
|
|
|
|
list_for_each_safe(pos, tmp, &AcPlcyList.List) {
|
|
node = list_entry(pos, AcPlcyNode, List);
|
|
|
|
switch (NewNode->RuleType) {
|
|
case AC_MAC_GROUP:
|
|
if (memcmp(node->Mac, NewNode->Mac, 6) == 0 &&
|
|
node->Type == NewNode->Type) {
|
|
return node;
|
|
}
|
|
break;
|
|
case AC_IP_GROUP:
|
|
if (node->IpS == NewNode->IpS
|
|
&& node->IpE == NewNode->IpE
|
|
&& node->Type == NewNode->Type) {
|
|
return node;
|
|
}
|
|
break;
|
|
case AC_VLAN_GROUP:
|
|
if (node->VLAN == NewNode->VLAN
|
|
&& node->Type == NewNode->Type) {
|
|
return node;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t AcAddNode(AcPlcyNode * NewNode)
|
|
{
|
|
AcPlcyNode *node = NULL;
|
|
|
|
if ((node = AcExistNode(NewNode))) {
|
|
return AC_SUCCESS;
|
|
}
|
|
|
|
node = (AcPlcyNode *) kmalloc(sizeof(AcPlcyNode), GFP_ATOMIC);
|
|
|
|
if (node == NULL) {
|
|
return AC_FAIL;
|
|
}
|
|
|
|
memcpy(node, NewNode, sizeof(AcPlcyNode));
|
|
node->AgIdx = PpeGetFreeAcGrp();
|
|
|
|
list_add_tail(&node->List, &AcPlcyList.List);
|
|
SyncAcTbl();
|
|
return AC_SUCCESS;
|
|
}
|
|
|
|
uint32_t AcDelNode(AcPlcyNode * DelNode)
|
|
{
|
|
struct list_head *pos = NULL, *tmp;
|
|
AcPlcyNode *node;
|
|
|
|
list_for_each_safe(pos, tmp, &AcPlcyList.List) {
|
|
node = list_entry(pos, AcPlcyNode, List);
|
|
|
|
switch (DelNode->RuleType) {
|
|
case AC_MAC_GROUP:
|
|
if (memcmp(node->Mac, DelNode->Mac, ETH_ALEN) == 0) {
|
|
goto found;
|
|
}
|
|
break;
|
|
case AC_IP_GROUP:
|
|
if (node->IpS == DelNode->IpS
|
|
&& node->IpE == DelNode->IpE) {
|
|
goto found;
|
|
}
|
|
break;
|
|
case AC_VLAN_GROUP:
|
|
if (node->VLAN == DelNode->VLAN) {
|
|
goto found;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return AC_FAIL;
|
|
|
|
found:
|
|
PpeSetFreeAcGrp(node->AgIdx);
|
|
list_del(pos);
|
|
kfree(node);
|
|
SyncAcTbl();
|
|
return AC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Pre Ac Function
|
|
*/
|
|
uint32_t PpeGetPreAcEbl(void)
|
|
{
|
|
uint32_t PpeFlowSet = 0;
|
|
|
|
PpeFlowSet = RegRead(PPE_FLOW_SET);
|
|
|
|
if ((PpeFlowSet & ~BIT_FUC_PREA) ||
|
|
(PpeFlowSet & ~BIT_FMC_PREA) || (PpeFlowSet & ~BIT_FBC_PREA)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
void PpeSetPreAcEbl(uint32_t PreAcEbl)
|
|
{
|
|
uint32_t PpeFlowSet = 0;
|
|
|
|
PpeFlowSet = RegRead(PPE_FLOW_SET);
|
|
|
|
/* Pre-Account engine for unicast/multicast/broadcast flow */
|
|
if (PreAcEbl == 1) {
|
|
PpeFlowSet |= (BIT_FUC_PREA);
|
|
#if defined (CONFIG_RA_HW_NAT_IPV6)
|
|
if (ipv6_offload)
|
|
PpeFlowSet |= (BIT_IPV6_PE_EN);
|
|
#endif
|
|
RegModifyBits(PPE_POL_CFG, DFL_POL_AC_PRD, 16, 16); //period
|
|
RegModifyBits(PPE_POL_CFG, 1, 13, 1); //enable Pre-account
|
|
|
|
} else {
|
|
PpeFlowSet &= ~(BIT_FUC_PREA | BIT_FMC_PREA | BIT_FBC_PREA);
|
|
#if defined (CONFIG_RA_HW_NAT_IPV6)
|
|
PpeFlowSet &= ~(BIT_IPV6_PE_EN);
|
|
#endif
|
|
/* We have to set period=0 first */
|
|
RegModifyBits(PPE_POL_CFG, 0, 16, 16); //period
|
|
RegModifyBits(PPE_POL_CFG, 0, 13, 1); //disable Pre-account
|
|
PpeRstPreAcPtr();
|
|
|
|
}
|
|
|
|
RegWrite(PPE_FLOW_SET, PpeFlowSet);
|
|
}
|
|
|
|
uint16_t PpeGetPreAcStr(void)
|
|
{
|
|
uint32_t PpePreAc = 0;
|
|
|
|
PpePreAc = RegRead(PPE_PRE_AC);
|
|
return PpePreAc & 0x1FF;
|
|
}
|
|
|
|
void PpeSetPreAcStr(uint16_t PreAcStr)
|
|
{
|
|
RegModifyBits(PPE_PRE_AC, PreAcStr, 0, 9);
|
|
}
|
|
|
|
uint16_t PpeGetPreAcEnd(void)
|
|
{
|
|
uint32_t PpePreAc = 0;
|
|
|
|
PpePreAc = RegRead(PPE_PRE_AC);
|
|
return (PpePreAc >> 16) & 0x1FF;
|
|
}
|
|
|
|
void PpeSetPreAcEnd(uint16_t PreAcEnd)
|
|
{
|
|
RegModifyBits(PPE_PRE_AC, PreAcEnd, 16, 9);
|
|
}
|
|
|
|
uint32_t PpeGetPostAcEbl(void)
|
|
{
|
|
uint32_t PpeFlowSet = 0;
|
|
|
|
PpeFlowSet = RegRead(PPE_FLOW_SET);
|
|
|
|
if ((PpeFlowSet & ~BIT_FUC_POSA) ||
|
|
(PpeFlowSet & ~BIT_FMC_POSA) || (PpeFlowSet & ~BIT_FBC_POSA)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
void PpeSetPostAcEbl(uint32_t PostAcEbl)
|
|
{
|
|
uint32_t PpeFlowSet = 0;
|
|
|
|
PpeFlowSet = RegRead(PPE_FLOW_SET);
|
|
|
|
/* Post-Account engine for unicast/multicast/broadcast flow */
|
|
if (PostAcEbl == 1) {
|
|
PpeFlowSet |= (BIT_FUC_POSA);
|
|
#if defined (CONFIG_RA_HW_NAT_IPV6)
|
|
if (ipv6_offload)
|
|
PpeFlowSet |= (BIT_IPV6_PE_EN);
|
|
#endif
|
|
RegModifyBits(PPE_POL_CFG, DFL_POL_AC_PRD, 16, 16); //period
|
|
RegModifyBits(PPE_POL_CFG, 1, 12, 1); //enable Post-account
|
|
|
|
} else {
|
|
PpeFlowSet &= ~(BIT_FUC_POSA | BIT_FMC_POSA | BIT_FBC_POSA);
|
|
#if defined (CONFIG_RA_HW_NAT_IPV6)
|
|
PpeFlowSet &= ~(BIT_IPV6_PE_EN);
|
|
#endif
|
|
/* We have to set period=0 first */
|
|
RegModifyBits(PPE_POL_CFG, 0, 16, 16); //period
|
|
RegModifyBits(PPE_POL_CFG, 0, 12, 1); //disable Post-account
|
|
PpeRstPostAcPtr();
|
|
|
|
}
|
|
|
|
RegWrite(PPE_FLOW_SET, PpeFlowSet);
|
|
|
|
}
|
|
|
|
uint16_t PpeGetPostAcStr(void)
|
|
{
|
|
uint32_t PpePostAc = 0;
|
|
|
|
PpePostAc = RegRead(PPE_POST_AC);
|
|
return PpePostAc & 0x1FF;
|
|
}
|
|
|
|
void PpeSetPostAcStr(uint16_t PostAcStr)
|
|
{
|
|
RegModifyBits(PPE_POST_AC, PostAcStr, 0, 9);
|
|
}
|
|
|
|
uint16_t PpeGetPostAcEnd(void)
|
|
{
|
|
uint32_t PpePostAc = 0;
|
|
|
|
PpePostAc = RegRead(PPE_POST_AC);
|
|
return (PpePostAc >> 16) & 0x1FF;
|
|
}
|
|
|
|
void PpeSetPostAcEnd(uint16_t PostAcEnd)
|
|
{
|
|
RegModifyBits(PPE_POST_AC, PostAcEnd, 16, 9);
|
|
}
|
|
|
|
void inline PpeInsAcEntry(void *Rule, enum AcType Type)
|
|
{
|
|
uint32_t Index = 0;
|
|
uint32_t *p = (uint32_t *) Rule;
|
|
|
|
if (Type == PRE_AC) {
|
|
Index = PpeGetPreAcEnd();
|
|
} else {
|
|
Index = PpeGetPostAcEnd();
|
|
}
|
|
|
|
NAT_DEBUG("Policy Table Base=%08X Offset=%d\n", POLICY_TBL_BASE, Index * 8);
|
|
NAT_DEBUG("%08X: %08X\n", POLICY_TBL_BASE + Index * 8, *p);
|
|
NAT_DEBUG("%08X: %08X\n", POLICY_TBL_BASE + Index * 8 + 4, *(p + 1));
|
|
|
|
RegWrite(POLICY_TBL_BASE + Index * 8, *p); /* Low bytes */
|
|
RegWrite(POLICY_TBL_BASE + Index * 8 + 4, *(p + 1)); /* High bytes */
|
|
|
|
/* Update AC_END */
|
|
if (Type == PRE_AC) {
|
|
PpeSetPreAcEnd(Index + 1);
|
|
} else {
|
|
PpeSetPostAcEnd(Index + 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* MAC
|
|
*/
|
|
uint32_t AcInsMac(AcPlcyNode * node)
|
|
{
|
|
struct l2_rule L2Rule;
|
|
|
|
memset(&L2Rule, 0, sizeof(L2Rule));
|
|
memcpy(&L2Rule.mac, node->Mac, ETH_ALEN);
|
|
|
|
L2Rule.com.rt = L2_RULE;
|
|
L2Rule.com.pn = PN_DONT_CARE;
|
|
L2Rule.com.match = 1;
|
|
|
|
L2Rule.com.ac.ee = 1;
|
|
L2Rule.com.ac.ag = node->AgIdx;
|
|
|
|
if (node->Type == PRE_AC) {
|
|
L2Rule.com.dir = SMAC;
|
|
PpeInsAcEntry(&L2Rule, PRE_AC);
|
|
} else { /* Post AC */
|
|
L2Rule.com.dir = DMAC;
|
|
PpeInsAcEntry(&L2Rule, POST_AC);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* IP
|
|
*/
|
|
uint32_t AcInsIp(AcPlcyNode * node)
|
|
{
|
|
struct l3_rule L3Rule;
|
|
uint8_t E, M;
|
|
|
|
memset(&L3Rule, 0, sizeof(L3Rule));
|
|
|
|
CalIpRange(node->IpS, node->IpE, &M, &E);
|
|
L3Rule.com.ee_0.ee = 1;
|
|
L3Rule.com.ac.ag = node->AgIdx;
|
|
|
|
L3Rule.com.match = 1;
|
|
L3Rule.com.pn = PN_DONT_CARE;
|
|
L3Rule.com.rt = L3_RULE;
|
|
L3Rule.ip.ip = node->IpS;
|
|
L3Rule.ip.ip_rng_m = M;
|
|
L3Rule.ip.ip_rng_e = E;
|
|
L3Rule.ip.v4 = 1;
|
|
|
|
if (node->Type == PRE_AC) {
|
|
L3Rule.com.dir = SIP;
|
|
PpeInsAcEntry(&L3Rule, PRE_AC);
|
|
} else { /* Post AC */
|
|
L3Rule.com.dir = DIP;
|
|
PpeInsAcEntry(&L3Rule, POST_AC);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* VLAN
|
|
*/
|
|
uint32_t AcInsVlan(AcPlcyNode * node)
|
|
{
|
|
struct l2_rule L2Rule;
|
|
|
|
memset(&L2Rule, 0, sizeof(L2Rule));
|
|
|
|
L2Rule.others.vid = node->VLAN;
|
|
L2Rule.others.v = 1;
|
|
|
|
L2Rule.com.rt = L2_RULE;
|
|
L2Rule.com.pn = PN_DONT_CARE;
|
|
L2Rule.com.match = 1;
|
|
|
|
L2Rule.com.ac.ee = 1;
|
|
L2Rule.com.ac.ag = node->AgIdx;
|
|
|
|
if (node->Type == PRE_AC) {
|
|
L2Rule.com.dir = OTHERS;
|
|
PpeInsAcEntry(&L2Rule, PRE_AC);
|
|
} else { /* Post AC */
|
|
L2Rule.com.dir = OTHERS;
|
|
PpeInsAcEntry(&L2Rule, POST_AC);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Remove all AC entries */
|
|
uint32_t AcCleanTbl(void)
|
|
{
|
|
struct list_head *pos = NULL, *tmp;
|
|
AcPlcyNode *node;
|
|
|
|
list_for_each_safe(pos, tmp, &AcPlcyList.List) {
|
|
node = list_entry(pos, AcPlcyNode, List);
|
|
list_del(pos);
|
|
kfree(node);
|
|
}
|
|
|
|
PpeSetPreAcEbl(0); // Disable PreAc Table
|
|
PpeSetPostAcEbl(0); // Disable PostAc Table
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/* Low High
|
|
* +-------------+-------------+
|
|
* |Byte_cnt(32) | Pkt_cnt(32) |
|
|
* +-------------+-------------+
|
|
*/
|
|
|
|
uint32_t AcGetCnt(AcPlcyNode * SearchNode, enum AcCntType AcCntType)
|
|
{
|
|
struct list_head *pos = NULL, *tmp;
|
|
AcPlcyNode *node;
|
|
long long result;
|
|
|
|
list_for_each_safe(pos, tmp, &AcPlcyList.List) {
|
|
node = list_entry(pos, AcPlcyNode, List);
|
|
|
|
switch (SearchNode->RuleType) {
|
|
case AC_MAC_GROUP:
|
|
if ((memcmp(node->Mac, SearchNode->Mac, ETH_ALEN)
|
|
== 0) && node->Type == SearchNode->Type) {
|
|
goto found;
|
|
}
|
|
break;
|
|
case AC_IP_GROUP:
|
|
if ((node->IpS == SearchNode->IpS) &&
|
|
(node->IpE == SearchNode->IpE) &&
|
|
(node->Type == SearchNode->Type)) {
|
|
goto found;
|
|
}
|
|
break;
|
|
case AC_VLAN_GROUP:
|
|
if ((node->VLAN == SearchNode->VLAN) &&
|
|
(node->Type == SearchNode->Type)) {
|
|
goto found;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
found:
|
|
if (AcCntType == AC_BYTE_CNT) {
|
|
result = RegRead(AC_BASE + node->AgIdx * 8);
|
|
return result;
|
|
} else { /* Packet Count */
|
|
result = RegRead(AC_BASE + node->AgIdx * 8 + 4);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
int PpeGetFreeAcGrp(void)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
for (j = 0; j < 8; j++) {
|
|
if ((AcFreeList[i] & (1 << j)) == 0) {
|
|
AcFreeList[i] |= (1 << j);
|
|
return (i * 8 + j);
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void PpeSetFreeAcGrp(uint32_t ag_idx)
|
|
{
|
|
AcFreeList[ag_idx / 8] &= ~(1 << (ag_idx % 8));
|
|
}
|