///*!Copyright(c) 2022-2025 Shenzhen TP-Link Technologies Co.,Ltd.
// *All rights reserved.
// *
// *\file srvcFpt.c
// *
// *\author caoyi1 <caoyi1@tp-link.net>
// *\version 1.0.0
// *\date 02/06/2025
// *
// *\history \args 1.0.0 02/06/2025, caoyi1, Create file.
// */
//
///**************************************************************************************************/
///* INCLUDE_FILES */
///**************************************************************************************************/
/*system header*/
#include "linux/ip.h"
/*common header*/
#include "fepTypes.h"
#include "fepDefs.h"
/* platform header */
#include "pal/msgq.h"
#include "pal/thread.h"
/* public application header */
#include "common/applError.h"
#include "fpt/errFpt.h"
/*service header*/
#include "timer/timer.h"
#include "userPort/user_port.h"
#define DBG_ON 1
#include "tpDbg/tpdebug.h"
/* application private header */
#include "data/dataFpt.h"
#include "srvcFpt.h"
#include "adFpt.h"
#include "midware/tpNotify.h"
#include "midware/tpRpc.h"
#include "gr/gr_thread.h"
#include "midware/fepPacket.h"
#include <net/if.h>
#include <time.h>
/**************************************************************************************************/
/* DEFINES */
/**************************************************************************************************/
/* name */
#define FPT_MOD_NAME "fpt"
#define FPT_DMP_MODIFY_RULE_NODE_NAME FPT_MOD_NAME"_dmp_modify_node"
#define FPT_CNT_CHECK_TIMER_NAME ("fpt_cnt_check_tm")
#define maxHandleLen 128
/**************************************************************************************************/
/* TYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* EXTERN_PROTOTYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* LOCAL_PROTOTYPES */
/**************************************************************************************************/
static UINT32 round_counter = 0;
static TIMER_ID fptCountCheckTimer; // 计数定时器
static struct timespec last_pkt_time = {}; //最后收包时间戳
static struct timespec current_time = {}; //当前时间戳
static int round = 0;
static FPT_ID globalFptId = 0;
static RULE_ID globalRuleId = 0;
static int isHashTableInitialized = 0; //哈希表是否创建
typedef struct ruleDataMap
{
UINT8 srcIp[4], dstIp[4];
UINT8 proto;
UINT16 sProt, dProt;
}ruleMap;
typedef struct HANDLE_DATA_STORE
{
FPT_ID fptId;
RULE_ID ruleId;
int round;
PKT_HANDLE fptHandle;
ruleMap rule;
struct timespec last_pkt_time;
}handleConfig;
/**************************************************************************************************/
/* VARIABLES */
/**************************************************************************************************/
//static TIMER_ID fptTimer;
//
//PKT_HANDLE *handleNetLink = NULL;
/**************************************************************************************************/
/* LOCAL_FUNCTIONS */
/**************************************************************************************************/
/* 生成规则唯一键 */
static char* _makeRuleKey(FPT_ID fptId, RULE_ID ruleId)
{
static char key[32];
snprintf(key, sizeof(key), "srvcFpt_%u_rule_%u", fptId, ruleId);
return key;
}
/* 查找或创建规则状态 */
static histStore* _getHandleCfgData(FPT_ID fptId, RULE_ID ruleId)
{
char* key = _makeRuleKey(fptId, ruleId);
ENTRY e = { .key = key, .data = NULL };
histStore* newHist = calloc(1, sizeof(histStore));
/* 哈希查找 */
ENTRY* ep = hsearch(e, FIND);
if (ep)
{
return (histStore*)ep->data;
}
/* 不存在则创建 */
if (!newHist)
{
return NULL;
}
e.data = newHist;
ep = hsearch(e, ENTER); // 插入哈希表
if (!ep)
{
free(newHist);
return NULL;
}
return newHist;
}
STATUS _srvcFptTimeStateUpdateCb(FEP_PACKET_SEND_T rcvMsg, int round)
{
int ret = ERR_NO_ERROR;
tpState_Obj *pSetObj = NULL;
pSetObj = tpState_objCreate();
char keyStr[TPSTATE_KEY_MAX_LEN] = { 0 };
char tblStr[TPSTATE_KEY_MAX_LEN] = { 0 };
// INT64 score = 0;
snprintf(tblStr, sizeof(tblStr), FPT_STATE_TIME_TBL);
snprintf(keyStr, sizeof(keyStr), FPT_STATE_TIME_KEY, globalFptId, globalRuleId, round);
PFM_IF_FAIL_DONE_RET(ret, tpState_objAddKey(pSetObj, keyStr), ERR_BAD_PARAM);
PFM_IF_FAIL_DONE_RET(ret, tpState_objAddFieldNumU64(pSetObj, FPT_STATE_TIME_SEC, rcvMsg.extraArg->commonArg.time_sec), ERR_BAD_PARAM);
PFM_IF_FAIL_DONE_RET(ret, tpState_objAddFieldNumU64(pSetObj, FPT_STATE_TIME_NSEC, rcvMsg.extraArg->commonArg.time_nanosec), ERR_BAD_PARAM);
PFM_IF_FAIL_DONE_RET(ret, tpState_onlySet(pSetObj, tblStr, TPSTATE_OPER_MOD_OR_ADD),ERR_BAD_PARAM);
printf("time data has been add to stateDB \r\n");
done:
if (pSetObj)
{
tpState_objFree(pSetObj);
}
return ret;
}
void _srvcCountTimeoutCheckHnd()
{
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
double time_diff = (current_time.tv_sec - last_pkt_time.tv_sec) + (current_time.tv_nsec - last_pkt_time.tv_nsec) * 1e-9;
// 5秒内无新包则重置计数器
if (time_diff > 5.0 && round_counter > 0)
{
round_counter = 0;
printf("Timeout: Reset rule_counter to 0\n");
}
}
static void _srvcConfigObj2IpRule(FPT_ID fptId, RULE_ID ruleId, tpConfig_Iter *iter, FPT_IP_RULE *ipRule)
{
char tblKey[TPOBJ_KEY_MAX_LEN] = {};
char *tmpStr = NULL;
UINT8 tmpU8 = 0;
UINT32 tmpU32 = 0;
APPL_ENSURE_RET_VOID(iter);
APPL_ENSURE_RET_VOID(ipRule);
snprintf(tblKey, TPOBJ_KEY_MAX_LEN, IP_FPT_RULE_IDX, fptId, ruleId);
ipRule->ruleId = ruleId;
TPCONFIG_ITER_FV(iter)
{
if (PFM_ERR_C_OK == tpConfig_IterGetStrPtr(iter, &tmpStr, tblKey, IP_FPT_RULE_SIP))
{
ipRule->ipRule.ipValid.sIpEnable = 1;
fptIpStr2IpArray(tmpStr, ipRule->ipRule.sourceAddress.ipAddr);
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetStrPtr(iter, &tmpStr, tblKey, IP_FPT_RULE_SIP_MASK))
{
ipRule->ipRule.ipValid.sIpEnable = 1;
fptIpStr2IpArray(tmpStr, ipRule->ipRule.sourceAddressMask.ipAddr);
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetStrPtr(iter, &tmpStr, tblKey, IP_FPT_RULE_DIP))
{
ipRule->ipRule.ipValid.dIpEnable = 1;
fptIpStr2IpArray(tmpStr, ipRule->ipRule.destAddress.ipAddr);
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetStrPtr(iter, &tmpStr, tblKey, IP_FPT_RULE_DIP_MASK))
{
ipRule->ipRule.ipValid.dIpEnable = 1;
fptIpStr2IpArray(tmpStr, ipRule->ipRule.destAddressMask.ipAddr);
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU8(iter, &tmpU8, tblKey, IP_FPT_RULE_LOGGING))
{
ipRule->logging = tmpU8;
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU8(iter, &tmpU8, tblKey, IP_FPT_RULE_IP_PROTO))
{
ipRule->ipRule.ipValid.ipProtoValid = 1;
ipRule->ipRule.ipProto = tmpU8;
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU32(iter, &tmpU32, tblKey, IP_FPT_RULE_SPORT))
{
ipRule->ipRule.ipValid.l4SourcePortValid = 1;
ipRule->ipRule.fptL4Struct.sport = tmpU32;
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU32(iter, &tmpU32, tblKey, IP_FPT_RULE_SPORT_MASK))
{
ipRule->ipRule.ipValid.l4SourcePortValid = 1;
ipRule->ipRule.fptL4Struct.spMask = tmpU32;
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU32(iter, &tmpU32, tblKey, IP_FPT_RULE_DPORT))
{
ipRule->ipRule.ipValid.l4DestPortValid = 1;
ipRule->ipRule.fptL4Struct.dport = tmpU32;
continue;
}
if (PFM_ERR_C_OK == tpConfig_IterGetNumU32(iter, &tmpU32, tblKey, IP_FPT_RULE_DPORT_MASK))
{
ipRule->ipRule.ipValid.l4DestPortValid = 1;
ipRule->ipRule.fptL4Struct.dpMask = tmpU32;
continue;
}
}
}
/**************************************************************************************************/
/* PUBLIC_FUNCTIONS */
/**************************************************************************************************/
STATUS fptFepPacketInit()
{
FEP_PACKET_INIT_T fepPKtParam = {};
fepPKtParam.channelCfgPath = FEP_PACKET_CHANNEL_CFG_PATH;
fepPKtParam.maxBuffSize = 2048;
fepPKtParam.maxSocketNum = 10;
PFM_IF_FAIL_RET_VAL(fepPacketInit(&fepPKtParam), ERR_INIT);
if (!isHashTableInitialized)
{
if ( 0 == hcreate(maxHentries) )
{
DE("srvc hcreate failed");
return ERR_NO_MEMORY;
}
else
{
isHashTableInitialized = !isHashTableInitialized;
}
}
return ERR_NO_ERROR;
}
void fptFepPacketCb(char *buff, UINT32 len, FEP_PACKET_EXTRA_T *extraArg)
{
FPT_ID fptId = 0;
RULE_ID ruleId = 0;
struct iphdr *ipHeader = (struct iphdr*)(buff + sizeof(struct ethhdr));
UINT8 proto = ipHeader->protocol;
UINT32 srcIp = ipHeader->saddr;
UINT32 dstIp = ipHeader->daddr;
APPL_ENSURE_RET_VOID(ret, 2 == sscanf(fptHandle, "fptHandle:fpt%d_rule%d", &fptId, &ruleId), ERR_BAD_PARAM);
clock_gettime(CLOCK_MONOTONIC, &last_pkt_time);
round_counter++;
FEP_PACKET_SEND_T rcvMsg = {};
rcvMsg.len = len;
rcvMsg.buffer = buff;
rcvMsg.extraArg = extraArg;
if (1 == rule_counter)
{
round ++ ;
_srvcFptTimeStateUpdateCb(globalFptId, globalRuleId, rcvMsg, round);
DW("first arrive timeStamp has been saved \r\n");
}
return ;
}
STATUS fptFepPacketCreateAfPkt(FPT_ID fptId, RULE_ID ruleId, FPT_IP_RULE *ipRule)
{
FEP_PACKET_CREATE_T param = { 0 };
FEP_PACKET_FILTER_T filter = { 0 };
FEP_PACKET_RULE_DATA_T ethTypeRule = { 0 };
FEP_PACKET_RULE_DATA_T procRule = { 0 };
FEP_PACKET_RULE_DATA_T srcIpRule = { 0 };
FEP_PACKET_RULE_DATA_T dstIpRule = { 0 };
FEP_PACKET_RULE_DATA_T actionRule = { 0 };
char fptHandle;
snprintf(fptHandle, 128, "fptHandle:fpt%d_rule%d", fptId, ruleId);
PKT_HANDLE fptHandle = NULL;
handleConfig* handleCfg = NULL;
handleCfg = _getHandleCfgData(fptId, ruleId);
handleCfg->fptId = fptId;
handleCfg->ruleId = ruleId;
handleCfg->rule.srcIp = ipRule->ipRule.sourceAddress;
handleCfg->rule.dstIp = ipRule->ipRule.destAddress;
handleCfg->rule.proto = ipRule->ipRule.ipProto;
UINT8 ethTpye[2] = {0x08, 0x00};
UINT8 ipProtocol[] = {ipRule->ipRule.ipProto};
UINT8 srcIp[] = {ipRule->ipRule.sourceAddress[0], ipRule->ipRule.sourceAddress[1], ipRule->ipRule.sourceAddress[2], ipRule->ipRule.sourceAddress[3]};
UINT8 dstIp[] = {ipRule->ipRule.destAddress[0], ipRule->ipRule.destAddress[1], ipRule->ipRule.destAddress[2], ipRule->ipRule.destAddress[3]};
param.handleName = "fptHandleDmpModify";
param.fillter = &filter;
param.dmpName = NULL;
filter.ruleListType = RX_LIST_PRIORITY_5;
filter.priority = -1; /* 越大优先级越低,注册在dmp默认送CPU节点前,防止影响其他模块 */
filter.modName = FPT_MOD_NAME;
filter.ruleNodeName = FPT_DMP_MODIFY_RULE_NODE_NAME;
filter.own = FEP_RX_NOT_OWNED;
filter.nodeNum = 5;
// filter.nodeNum = 3;
/* 以太网类型 */
ethTypeRule.value = ethTpye;
ethTypeRule.len = sizeof(ethTpye);
filter.node[0].nodeType = PACKET_FILTER_MATCH;
filter.node[0].filterType = FEP_PACKET_MATCH_NETWORK;
filter.node[0].filterRule = FEP_PACKET_MATCH;
filter.node[0].pos = FEP_PACKET_NODE_POS_TAIL;
filter.node[0].rule = ðTypeRule;
/* 三层协议 */
procRule.value = ipProtocol;
procRule.len = sizeof(ipProtocol);
filter.node[1].nodeType = PACKET_FILTER_MATCH;
filter.node[1].filterType = FEP_PACKET_MATCH_TRANSPORT;
filter.node[1].filterRule = FEP_PACKET_MATCH;
filter.node[1].pos = FEP_PACKET_NODE_POS_TAIL;
filter.node[1].rule = &procRule;
/* 源ip */
srcIpRule.value = srcIp;
srcIpRule.len = sizeof(srcIp);
filter.node[2].nodeType = PACKET_FILTER_MATCH;
filter.node[2].filterType = FEP_PACKET_MATCH_NETWORK_SRC_IPV4;
filter.node[2].filterRule = FEP_PACKET_MATCH;
filter.node[2].pos = FEP_PACKET_NODE_POS_TAIL;
filter.node[2].rule = &srcIpRule;
/* 目的ip */
dstIpRule.value = dstIp;
dstIpRule.len = sizeof(dstIp);
filter.node[3].nodeType = PACKET_FILTER_MATCH;
filter.node[3].filterType = FEP_PACKET_MATCH_NETWORK_DST_IPV4;
filter.node[3].filterRule = FEP_PACKET_MATCH;
filter.node[3].pos = FEP_PACKET_NODE_POS_TAIL;
filter.node[3].rule = &dstIpRule;
/* action */
filter.node[4].nodeType = PACKET_FILTER_ACTION;
filter.node[4].filterType = FEP_PACKET_ACTION_SEND_TO_PROC;
filter.node[4].pos = FEP_PACKET_NODE_POS_TAIL;
filter.node[4].rule = &actionRule;
fptHandle = fepPacketCreate(¶m);
APPL_ENSURE_RET_VAL(NULL != fptHandle, ERR_INIT);
handleCfg->fptHandle = fptHandle;
PFM_IF_FAIL_RET(fepPacketRecvAdd(fptHandle, fptFepPacketCb));
return ERR_NO_ERROR;
}
STATUS fptFepPacketDestroy(FPT_ID fptId, RULE_ID ruleId)
{
handleConfig* handleCfg = NULL;
PKT_HANDLE fptHandle = NULL;
handleCfg = _getHandleCfgData(fptId, ruleId);
fptHandle = handleCfg->fptHandle;
fepPacketDestroy(fptHandle);
return ERR_NO_ERROR;
}
STATUS srvcFptRuleDispatch(tpConfig_Iter *iter)
{
char* keyName = NULL;
FPT_ID fptId = 0;
RULE_ID ruleId = 0;
FPT_TYPE_MODE fptType = FPT_TYPE_IP;
FPT_RULE_UNION fptRule = {};
/* 删除rule */
if (TPCONFIG_IS_DELETE(iter))
{
TPCONFIG_ITER_KEY(iter)
{
keyName = tpConfig_getKeyName(iter);
APPL_ENSURE_RET(2 == sscanf(keyName, FPT_RULE_IDX, &fptId, &ruleId));
APPL_IF_ERR_RET(fptFepPacketDestroy(fptId, ruleId));
}
return ERR_NO_ERROR;
}
/* 添加rule */
TPCONFIG_ITER_KEY(iter)
{
keyName = tpConfig_getKeyName(iter);
APPL_ENSURE_RET(2 == sscanf(keyName, FPT_RULE_IDX, &fptId, &ruleId));
memset(&fptRule, 0, sizeof(FPT_RULE_UNION));
APPL_IF_ERR_RET(fptId2Type(fptId, &fptType));
switch (fptType)
{
case FPT_TYPE_IP:
_srvcConfigObj2IpRule(fptId, ruleId, iter, &fptRule.ipRule);
APPL_IF_ERR_RET(fptFepPacketCreateAfPkt(fptId, ruleId, (void *)&fptRule.ipRule));
break;
default:
return ERR_FPT_FPT_TYPE_INVALID;
// DBG_INFO_ERROR("bad type.");
}
}
return ERR_NO_ERROR;
}
//STATUS srvcFptPktUpdate()
//{
// TPDATA_OBJ *obj = tpDataObjCreate(TPDATA_OBJ_DEF_INIT);
// if (ERR_NO_ERROR == dataFptAllActionGet(obj))
// {
// PFM_IF_FAIL_RET(fepPacketRecvAdd(fptHandle, fptFepPacketCb)); // 开启收包
// }
// else
// {
// PFM_IF_FAIL_RET(fepPacketRecvRemove(fptHandle)); // 关闭收包
// }
//
// return ERR_NO_ERROR;
//}
//STATUS fptFepPacketDeInit()
//{
// APPL_IF_ERR_RET(fepPacketRecvRemove(fptHandle)); // 关闭收包
// APPL_IF_ERR_RET(fptFepPacketRuleUnReg());
// fepPacketDeInit();
// return ERR_NO_ERROR;
//}
//
//
//STATUS srvcPppoeFepPacketDeinit()
//{
// APPL_IF_ERR_RET(fptFepPacketDeInit());
// return ERR_NO_ERROR;
//}
//
//
//STATUS srvcFptFepPacketInit()
//{
//// APPL_IF_ERR_RET(fptFepPacketInit()); // fepPacket初始化
// APPL_IF_ERR_RET(fptFepPacketCreateAfPkt()); // 创建收发包规则
// return ERR_NO_ERROR;
//}
//
//STATUS fptFepPacketRuleUnReg()
//{
// fepPacketDestroy(fptHandle); // 删除收发包规则
// return ERR_NO_ERROR;
//}
STATUS srvcFptFepPacketInit()
{
tpConfig_Obj* pSubObj = tpConfig_objCreate();
APPL_ENSURE_RET_VAL(pSubObj, ERR_NO_MEMORY);
/* fepPacket初始化 */
APPL_IF_ERR_RET(fptFepPacketInit());
/* 创建收发包规则 */
// (fptFepPacketCreateAfPkt());
/* 开启收包 */
// PFM_IF_FAIL_RET(fepPacketRecvAdd(fptHandle, fptFepPacketCb));
/* 订阅消息发布者 */
PFM_IF_FAIL_RET(tpConfig_dispatchSubReg(pSubObj, FPT_MODULE_NAME));// 订阅 FPT 模块的配置变更
/* 结束普通消息订阅 */
PFM_IF_FAIL_RET(tpConfig_dispatchSubEnd(pSubObj, TPCONFIG_CHANNEL_DATA_TYPE));
/* 注册Key回调 */
PFM_IF_FAIL_RET(tpConfig_dispatchFunReg(IP_FPT_RULE_ALL, (char *)srvcFptRuleDispatch));
/* 检查收包是否恒定的计时器 */
struct timespec CheckTm = {};
CheckTm.tv_sec = 1;
CheckTm.tv_nsec = 0; /* 1s 更新一次 */
/* 定时刷新命中计数 */
fptCountCheckTimer = add_timer(FPT_CNT_CHECK_TIMER_NAME, &CheckTm, _srvcCountTimeoutCheckHnd, NULL, 0, EXECUTE_FOREVER);
APPL_ENSURE_RET_VAL(TIMER_ID_IS_VALID(fptCountCheckTimer), ERR_INIT);
return ERR_NO_ERROR;
}
只需要告诉我如何在fptFepPacketCb中根据proto、srcIp及dstIp反向寻找哈希键